noip模拟10
发现是前几天早上那场 MX(美熙) 的模拟赛,但是没做。
A 王国边缘
其实知道是倍增题。但是想不出来怎么个倍增法。
于是用分块打上了部分分 分。
我们用倍增设 表示从 开始移动 次之后到达的下标的相对位置, 表示从 开始移动 次后到达的位置之前的完整周期个数。
然后对询问二进制拆分即可。
当然也可以把循环周期当作一个个有向边,在基环树上跑倍增。
点击查看代码
#include<bits/stdc++.h> using namespace std; #define int long long const int N=2e5+5; const int mod=1e9+7; int n,q,m,s[N],t[60][N],t2[60][N]; signed main() { // ios::sync_with_stdio(false); // cin.tie(0),cout.tie(0); cin>>n>>m>>q; int l=-m; for(int i=0;i<n;i++) { char c;cin>>c; if(c=='1') s[i]=i,l=i; else s[i]=l; } if(l!=-m) { for(int i=0;i<n&&s[i]==-m;i++)s[i]=l-n; } for(int i=0;i<n;i++) { int k=(i+m)%n; t[0][i]=max(i+m-k+s[k],i+1); t2[0][i]=t[0][i]%n; t[0][i]%=mod; } // cout<<"sss\n"; for(int i=1;i<60;i++) { for(int j=0;j<n;j++) { int k=t2[i-1][j]; t2[i][j]=t2[i-1][k]; t[i][j]=(t[i-1][k]-k+t[i-1][j])%mod; } } while(q--) { int s,k,s2; cin>>s>>k; s--;s2=s%n; for(int i=0;k;k>>=1,i++) { if(k&1) { s=(t[i][s2]+s-s2)%mod; s2=t2[i][s2]; } } cout<<(s+1)%mod<<"\n"; } }
B 买东西题
知道是贪心,但是不知道怎么贪。。。
考场上想到了维护每个数的价差 ,并且知道对于一个所有可用的优惠券集合,匹配最优的一定是价差最大的与优惠券减价最多的。
但是没想到可以看作每个数的价差也应该视作一张优惠券(其实猜到了,没敢想),一起维护在优惠券集合内,当你现在要反悔,第 个点要拿走第 个点的优惠券,那么他应该交换而不是直接拿。就是把 的价差维护进优惠券集合,拿走 的优惠券,就好了。
为了保证优惠券一定可用,就需要把优惠券和商品分别按 升序排列,依次将前缀的优惠券加入优先队列中维护。
和正解就差一行代码!!!
点击查看代码
#include<bits/stdc++.h> using namespace std; #define int long long int n,m; const int N=1e6+5; struct node1{ int a,b; inline bool operator<(const node1 &ll) const{ if(ll.b==b) return ll.a>a; return ll.b>b; } }c[N]; struct node{ int a,b,c; inline bool operator<(const node &ll) const{ if(ll.c==c) return ll.a>a; if(ll.a==a) return ll.b>b; return ll.c<c; } }e[N]; inline bool cmp(node a,node b) { // if(a.a==b.a) return a.b>b.b; // return min(a.a,b.a)>min(a.b,b.b); if(a.a==b.a) return a.b>b.b; return a.a<b.a; } inline bool cmp1(node1 a,node1 b)//实际上这几个是一样的,只是在不同的部分分和结构体内。 { if(a.a==b.a) return a.b>b.b; return a.a<b.a; } inline bool cmp2(node a,node b) { // if(a.a==b.a) return a.b>b.b; // return min(a.a,b.a)>min(a.b,b.b); if(a.a==b.a) return a.b<b.b; return a.a<b.a; } inline bool cmp3(node1 a,node1 b) { if(a.a==b.a) return a.b<b.b; return a.a<b.a; } priority_queue<node1>q; priority_queue<node>q1;//实际上没有用到它 signed main() { // freopen("buy5.in","r",stdin); freopen("buy.in","r",stdin); freopen("buy.out","w",stdout); ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n>>m; bool _=1; for(int i=1;i<=n;i++) cin>>e[i].a>>e[i].b,e[i].c=(e[i].a-e[i].b),_&=(e[i].a==e[i].b); for(int i=1;i<=m;i++) cin>>c[i].a>>c[i].b; if(_||n<=10) { sort(e+1,e+1+n,cmp); sort(c+1,c+1+m,cmp1); int ans=0,cnt=0; for(int i=1,j=1;i<=n;i++) { while(c[j].a<=e[i].a&&j<=m)q.push(c[j++]); // cout<<j<<" "; if(!q.empty()&&e[i].a-q.top().b<e[i].b) ans+=e[i].a-q.top().b,q.pop(),++cnt; else ans+=e[i].b; // cout<<"c: "<<c[i].a<<" "<<c[i].b<<"\n"; // cout<<"e: "<<e[i].a<<" "<<e[i].b<<"\n"; // cout<<ans<<"\n"; } cout<<ans;return 0; } sort(e+1,e+1+n,cmp2); sort(c+1,c+1+m,cmp3); int ans=0,cnt=0,j=1; for(int i=1;i<=n;i++) { while(j<=m&&c[j].a<=e[i].a) q.push(c[j++]); if(q.empty()||e[i].c>q.top().b) ans+=e[i].b; else ans+=e[i].a-q.top().b,q.pop(),q.push({1,e[i].a-e[i].b});//就是这个 push 没写出来 } // for(int i=1;i<=n;i++) q1.push(e[i]); // for(int i=1;i<=m;i++) q.push(c[i]); // while(!q1.empty()) // { // if(q.top().b<q1.top().c) ans+=q1.top().b,q1.pop(); // else ans+=q1.top().a-q.top().b,q.pop(),q1.pop(); // } cout<<ans;//其他的都是奇奇怪怪的假做法和部分分。 // for(int i=1;i<=n;i++) cout<<"q "<<q1.top().a<<" "<<q1.top().b<<"\n",q1.pop(); // return 0; // for(int i=1;i<=m;i++) // { // while(c[i].a<=e[j].a&&j<=n)q1.push(e[j++]); //// cout<<i<<" "; //// cout<<q1.top().a<<" "<<q1.top().b<<"\n"; //// cout<<"c: "<<c[i].a<<" "<<c[i].b<<"\n"; // q.push(c[i]); // if(!q1.empty()&&q1.top().c<q.top().b)ans+=q1.top().a-q.top().b,q1.pop(),++cnt,q.pop(); // else if(!q1.empty())ans+=q1.top().b,q1.pop(); //// cout<<"ans: "<<ans<<"\n"; // } //// cout<<ans<<"\n"; //// cout<<j<<"\n"; // for(int i=j;i<=n;i++) q1.push(e[i]); // while(!q1.empty()) ans+=q1.top().b,q1.pop(); // cout<<ans; }
C IMAWANOKIWA (Construction ver.)
分讨+构造。
首先,对于 ans1,有结论:
-
当且仅当 全为 时答案为 ;
-
序列 没有 时答案为 的个数对 取模的余数+1;
-
否则,当且仅当序列 为 (其中 可用没有)的形式时,答案为 ,否则为 。
还有结论,第一个能合并的位置移动不超过 。
那么就可以每次合并前几个,用上面的三个结论试一下答案是否会被改变,如果没有那么保留。
好像有 分。
tj:
点击查看代码
#include<bits/stdc++.h> using namespace std; #define int long long #define ull unsigned long long const int N=100007,op[3][3]={{0,1,1},{1,1,2},{1,2,1}}; const ull pp=13331; int T,n,a[N],k,p,last0; char s[N]; ull ans; signed main() { freopen("popc.in","r",stdin); freopen("popc.out","w",stdout); ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); cin>>T; while(T--) { cin>>(s+1); n=strlen(s+1); k=a[1]=s[1]-'0',ans=0; for(int i=2;i<=n;++i) a[i]=s[i]-'0',k=op[k][a[i]]; if(k<2) { cout<<k<<" "; for(int i=1;i<n;++i) ans=ans*pp+1; cout<<ans<<"\n"; continue; } last0=0; for(int i=n;i;--i) { if(!a[i]) { last0=i;break; } } if(!last0) { cout<<k<<" "; for(int i=1;i<n;++i) ans=ans*pp+1; cout<<ans<<"\n"; continue; } bool fl=0; for(int i=1;i<last0;++i) fl|=(bool)a[i]; if(!fl) { cout<<"1 "; k=a[last0+1];p=last0+1; for (int i=1;i<last0;++i) ans=ans*pp+1; while(k==a[last0+1]) { ans=ans*pp+2;k=op[k][a[++p]]; } for(int i=0;i<=n-p;++i) ans=ans*pp+1; cout<<ans<<'\n'; continue; } k=a[1]; for(int i=2;i<last0;++i) { ans=ans*pp+1,k=op[k][a[i]]; } int tmp=a[last0+1],p=last0+1; while(k==tmp&&p<=n) { tmp=op[tmp][a[++p]];ans=ans*pp+3; } if(p<=n) { ans=ans*pp+2; for(int i=0;i<=n-p;++i) ans=ans*pp+1; cout<<"1 "<<ans<<'\n';continue; } ans=0; tmp=a[last0-1];p=last0-1; while(tmp!=1&&p)tmp=op[tmp][a[--p]]; if(!p) { cout<<"2 "; for(int i=1;i<n;++i) ans=ans*pp+1; cout<<ans<<'\n'; continue; } cout<<"1 "; k=a[1]; for(int i=2;i<p;++i) { k=op[k][a[i]],ans=ans*pp+1; } if(a[p]==0) { if(k==1) { for(int i=2;i<last0-p;++i) ans=ans*pp+3; ans=((ans*pp+2)*pp+1)*pp+2; for(int i=1;i<=n-last0;++i) ans=ans*pp+1; cout<<ans<<'\n'; } else if(k==2) { if(last0==p+2) { ans=(ans*pp+2)*pp+2; for(int i=1;i<n-p;++i) ans=ans*pp+1; cout<<ans<<'\n'; } else { ans=ans*pp+2; for(int i=1;i<last0-p;++i) ans=ans*pp+1; ans=ans*pp+2; for(int i=1;i<=n-last0;++i) ans=ans*pp+1; cout<<ans<<'\n'; } } else { if(p>1) ans=ans*pp+1; if(last0==p+2) { ans=(ans*pp+1)*pp+2; for(int i=1;i<=n-last0;++i) ans=ans*pp+1; cout<<ans<<'\n'; } else { for(int i=2;i<last0-p;++i) ans=ans*pp+2; ans=(ans*pp+1)*pp+2; for(int i=1;i<=n-last0;++i) ans=ans*pp+1; cout<<ans<<'\n'; } } } else { if(k==2) { for(int i=1;i<=last0-p;++i) ans=ans*pp+2; for(int i=0;i<=n-last0;++i) ans=ans*pp+1; cout<<ans<<'\n'; } else { for(int i=1;i<last0-p;++i) ans=ans*pp+2; ans=(ans*pp+1)*pp+2; for(int i=1;i<=n-last0;++i) ans=ans*pp+1; cout<<ans<<'\n'; } } } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!