Setsuna的K数列
题解:通过分析题目数据可得,由于每一轮中每一个数只能选择一次,那么最后s数组中的每一个数都可以通过二进制,二进制的每一位表示对应上一个数组中对应位是否选择,所以可以直接判断N的二进制位得出答案
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1000,mod=1e9+7;
typedef long long LL;
void solve()
{
int n,k;
cin>>n>>k;
int sum=0,a=1;
while(n)
{
if(n&1) sum=(sum+a)%mod;
a=a*(LL)k%mod;
n>>=1;
}
cout<<sum<<endl;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--){
solve();
}
return 0;
}
wiki下象棋
题解:特判一下马脚即可
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=300+9,M=N*N+9;
int mp[N][N];
int n,m,k,a,b,c,d;
int ans1,ans2;
int vis[N][N];
struct node {
int x,y,step;
};
int dx[]={-1,-2,-2,-1,1,2,2,1};
int dy[]={-2,-1,1,2,2,1,-1,-2};
int bfs1(){
queue<node>q;
while(q.size())q.pop();
q.push({a,b,0});
vis[a][b]=1;
if(a==c&&b==d)return 0;
while(q.size()){
auto p=q.front();
q.pop();
for(int i=0;i<8;i++){
int nx=dx[i]+p.x,ny=dy[i]+p.y;
if(nx<1||nx>n||ny<1||ny>m)continue;
if(vis[nx][ny])continue;
if(mp[nx][ny]==-1)continue;
vis[nx][ny]=1;
if(nx==c&&ny==d){
return p.step+1;
}
q.push({nx,ny,p.step+1});
}
}
return -1;
}
int nox[]={0,-1,-1,0,0,1,1,0};
int noy[]={-1,0,0,1,1,0,0,-1};
int bfs2(){
queue<node>q;
while(q.size())q.pop();
q.push({a,b,0});
vis[a][b]=1;
if(a==c&&b==d)return 0;
while(q.size()){
auto p=q.front();
q.pop();
for(int i=0;i<8;i++){
int nx=dx[i]+p.x,ny=dy[i]+p.y;
int nnx=p.x+nox[i],nny=p.y+noy[i];
if(nx<1||nx>n||ny<1||ny>m)continue;
if(mp[nx][ny]==-1)continue;
if(mp[nnx][nny]==-1)continue;
if(vis[nx][ny])continue;
vis[nx][ny]=1;
if(nx==c&&ny==d){
return p.step+1;
}
q.push({nx,ny,p.step+1});
}
}
return -1;
}
int main(){
std::ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int T;
cin>>T;
while(T--){
memset(vis,0,sizeof vis);
ans1=ans2=0;
cin>>n>>m>>k>>a>>b>>c>>d;
memset(mp,0,sizeof mp);//!!
while(k--){
int x,y;
cin>>x>>y;
mp[x][y]=-1;
}
// cout<<"---"<<endl;
cout<<bfs1()<<" ";
memset(vis,0,sizeof vis);
cout<< bfs2()<<"\n";
}
return 0;
}
天气预报
题解:首先本题所选的区间,只需要连续且满足两个条件即可,并且我们发现,区间越长越好,所以我们可以通过枚举确定左区间,然后二分找出最小右区间,就可以直接得出答案。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
int a[N];//用于存储前i天有多少天是晴天
char ss[N];
int main(){
ll n,x,y;
cin>>n>>x>>y;
scanf("%s",ss+1);//表示从下标为1的数组开始记录
for(int i=1;i<=n;i++){
a[i]=a[i-1];
if(ss[i]=='0')a[i]++;
}
ll res=0;
//先枚举确定左区间,然后再二分确定最小右区间
for(int i=1;i<=n;i++){
int l=i,r=n;
while(l<=r){
ll mid=l+r>>1;
ll rest=a[mid]-a[i-1];
if(rest>=x&&(mid-i+1)-rest>=y)r=mid-1;
else l=mid+1;
}
ll rest=a[r+1]-a[i-1];
ll p=(r+1-i+1)-rest;
if(rest>=x&&p>=y)
res+=(n-r);
}
if(x+y==0)res+=1;//排除边界情况
cout<<res;
}
叠硬币
题解:01背包,具体看代码
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9;
int arr[N];
int dp[N];
int main(){
int n,h;
cin>>n>>h;
for(int i=1;i<=n;i++){
cin>>arr[i];
}
sort(arr+1,arr+1+n);//对数组从小到大排序
memset(dp,0x3f,sizeof dp);//求最小值 赋值最大
dp[0]=0;//边界条件
for(int i=1;i<=n;i++){
for(int j=h;j>=arr[i];j--){
dp[j]=min(dp[j],dp[j-arr[i]]+1);
}
}
//如果高度为h,且他没有被更新过
if(dp[h]==0x3f3f3f3f)cout<<"-1\n";
else {
cout<<dp[h]<<"\n";//最少有几堆
int p=dp[h];
p--;
for(int i=1;i<=n;i++){//枚举数组中的堆数
if(dp[h-arr[i]]==p){//高度减去(某一堆)的高度剩下的堆数最少有几堆;
cout<<arr[i]<<" ";//输出该数组
h-=arr[i];//将高度减去这一堆的高度
p--;//堆数减减
}
}
}
return 0;
}
取模
题解:
代码:
#include <bits/stdc++.h>
using namespace std;
#define PII pair<int,int>
#define int long long
const int N = 2e4+10;
int n,k;
const int mod=998244353;
const int inv2=(998244353+1)/2;
void solve(){
cin>>n;
int ans=(n % mod)*(n % mod) %mod;
for(int i=1,r;i<=n;i=r+1){
r=n/(n/i);//相同商的右端点
ans-=(n/i)%mod*((r+i)%mod)%mod*((r+1-i)%mod)%mod*inv2%mod;
ans=(ans%mod+mod)%mod;
}
cout<<ans<<'\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--){
solve();
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod = 998244353;
LL pows(LL a, LL x, LL p){if(x==0)return 1; LL t = pows(a, x>>1,p);if(x%2==0)return t*t%p;return t*t%p*a%p;}
int main(){
LL n; cin>>n;
LL xx=pows(2LL,mod-2,mod);
LL ans=(n%mod)*(n%mod)%mod;
LL ret=sqrt(n);
LL tmp=n/(ret+1);
for(int i=1;i<=tmp;i++){
ans=(ans-n/i*i)%mod;
}
for(int i=n/(tmp+1);i>0;i--){
LL a=n/i; a %= mod;
LL b=n/(i+1)+1; b %= mod;
LL cnt=(((LL)i*((a+b))%mod)%mod*(a-b+1)%mod+mod)*xx%mod;
ans=(ans-cnt+mod)%mod;
}
cout<<(ans%mod+mod)%mod<<endl;
return 0;
}
剪绳子
题解:非常简单的一个题,只需要用set维护一下每次剪开的那些点,查询时直接二分查找最后一个+小于等于该店的数以及第一个大于的数,两点相减就是最后的答案。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5+10;
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int q; cin>>q;
set<float>se;
se.insert(0);
se.insert(10);
while(q--){
string op; float x; cin>>op>>x;
if(op=="C"){
se.insert(x);
}else{
auto p1=lower_bound(se.begin(),se.end(),x);
auto p2=upper_bound(se.begin(),se.end(),x);
if(p2==se.end())printf("%.5f\n",10-(*--p1));
else printf("%.5f\n",(*p2)-(*--p1));
}
}
return 0;
}
截肢葛瑞智
题解:比较简单的模拟