Educational Codeforces Round 157 (Rated for Div. 2)

F. Fancy Arrays

第一眼感觉是去容斥掉条件 1,因为条件 2 其实挺紧的。

不妨用 f(l,r) 表示 a 值域在 [l,r] 的方案(满足条件 2)。

那么答案为 f(0,+)f(0,x1)f(x+k,+),因为如果选了 [0,x1] 的数,那么还要更大的话,一定会选到 [x,x+k1],所以你要钦定没有的话,一定只能在 [0,x1] 里面选。>x+k1 同理。

考虑 + 的上界很烦,能不能合并下消去,f(0,+)f(x+k,+) 是啥?显然是存在一个数在 [0,x+k1] 的方案数。抽象到二维平面上便可以很好的解释。或者考虑二者的集合对称差,显然是 [0,x+k1] 这意味着二者减去之后一定是存在一个数在 [0,x+k1] 的方案数。考虑咋做。这个东西等价于最小值在这个区间的方案数,考虑钦定差分数组,接下来,记差分数组的前缀最小值为 mi,那么最小值显然为 a1+mi,考虑钦定 a1+mi 落在那个区间即可。而你会发现,我们这样钦定实际上对于差分数组是没有限制的。那这样钦定一定不重不漏吗?考虑一个序列,显然一定会被钦定到。接下来,再考虑一个序列,会被钦定几次?你注意到,对于一种确定的差分数组,其最小值的位置/位置集是唯一的。也就是说,我们钦定后,构造出来的一定是互不相同的。

接下来 f(0,x1) 这一部分直接 dp 即可。注意到,这种东西实际上是可以抽象成 DAG 数路径数的,这东西直接矩阵加速即可。

#include <bits/stdc++.h> #define int long long #define pb push_back using namespace std; const int mod=(int)(1e9+7); int n,K,X; int fpow(int x,int y) { int res=1; x%=mod; while(y) { if(y&1) res=res*x%mod; y>>=1; x=x*x%mod; } return res; } struct Mat { int a[41][41]; Mat() { memset(a,0,sizeof(a)); } void clr() { memset(a,0,sizeof(a)); } }E,F; Mat mul(Mat &f,Mat &g) { Mat res; for(int i=0;i<X;i++) for(int j=0;j<X;j++) for(int k=0;k<X;k++) res.a[i][j]=(res.a[i][j]+f.a[i][k]*g.a[k][j]%mod)%mod; return res; } void sol() { cin>>n>>X>>K; int ans=fpow(2*K+1,n-1)*(X+K)%mod; E.clr(); F.clr(); for(int i=0;i<X;i++) F.a[0][i]=1; for(int i=0;i<X;i++) { for(int j=0;j<X;j++) { if(abs(i-j)<=K) E.a[i][j]=1; } } int qwq=n-1; while(qwq>0) { if(qwq&1) F=mul(F,E); qwq>>=1; E=mul(E,E); } for(int i=0;i<X;i++) ans=(ans-F.a[0][i]+mod)%mod; cout<<(ans%mod+mod)%mod<<'\n'; } signed main() { cin.tie(0); ios::sync_with_stdio(false); int T; cin>>T; while(T--) sol(); return 0; }

E.Infinite Card Game

注意到类似省选那个过河卒,是个图上走的问题。

但是直接建图是平方级别。

考虑贪心地对于能赢的尽量选防御最大即可。

#include <bits/stdc++.h> #define int long long #define pb push_back using namespace std; const int N=(int)(6e5+5); struct node { int x,y; }a[N],b[N]; int vis[N]; vector<int>g[N]; int n,fl,m,pre[N],prep[N],du[N]; queue<int>q; bool cmp(const node &x,const node &y) { return x.x>y.x; } void sol() { cin>>n; for(int i=1;i<=n;i++) cin>>a[i].x; for(int i=1;i<=n;i++) cin>>a[i].y; cin>>m; for(int i=1;i<=m;i++) cin>>b[i].x; for(int i=1;i<=m;i++) cin>>b[i].y; sort(b+1,b+1+m,cmp); sort(a+1,a+1+n,cmp); for(int i=1;i<=m;i++) { pre[i]=pre[i-1]; prep[i]=prep[i-1]; if(b[i].y>pre[i]) { pre[i]=b[i].y; prep[i]=i; } } for(int i=1;i<=n;i++) { int l=1,r=m,res=0; while(l<=r) { int mid=(l+r)>>1; if(b[mid].x>a[i].y) res=mid,l=mid+1; else r=mid-1; } if(res) g[n+prep[res]].pb(i),++du[i]; } for(int i=1;i<=n;i++) { pre[i]=pre[i-1]; prep[i]=prep[i-1]; if(a[i].y>pre[i]) { pre[i]=a[i].y; prep[i]=i; } } for(int i=1;i<=m;i++) { int l=1,r=n,res=0; while(l<=r) { int mid=(l+r)>>1; if(a[mid].x>b[i].y) res=mid,l=mid+1; else r=mid-1; } if(res) g[prep[res]].pb(n+i),++du[n+i]; } int ans1=0,ans2=0,ans3=0; for(int i=1;i<=n;i++) if(!du[i]) vis[i]=1,q.push(i); for(int i=1;i<=m;i++) if(!du[i+n]) vis[i+n]=3,q.push(i+n); while(!q.empty()) { int x=q.front(); q.pop(); for(int y:g[x]) { --du[y]; if(!du[y]) { vis[y]=vis[x]; q.push(y); } } } for(int i=1;i<=n;i++) { if(du[i]) ++ans2; if(vis[i]==1) ++ans1; if(vis[i]==3) ++ans3; } cout<<ans1<<" "<<ans2<<" "<<ans3<<"\n"; for(int i=0;i<=n+m;i++) g[i].clear(),vis[i]=du[i]=0; } signed main() { cin.tie(0); ios::sync_with_stdio(false); int T; cin>>T; while(T--) sol(); return 0; }

D.XOR Construction

注意到如果确定了第一个,其他一定是确定的。

bi=prei1 xor b1prea 的前缀异或。

那么限制有两个,一个是均不相同。

不妨考虑相同,即 prei1 xor b1=prej1 xor b1,即二者 pre 相同,这与我们选取 b1 是无关的。

另一个限制就是最大的数 n1,这个限制我们直接变成 check 每个开头是否合法,变成最大异或扔到 01trie 上即可。

#include <bits/stdc++.h> //#define int long long #define pb push_back using namespace std; const int N=(int)(4e5+5); int n,a[N],b[N],pre[N],ch[2][N*22],tot=1; void ins(int x) { int p=1; for(int i=20;i>=0;i--) { bool c=((x>>i)&1); if(!ch[c][p]) ch[c][p]=++tot; p=ch[c][p]; } } int qry(int x) { int res=0,p=1; for(int i=20;i>=0;i--) { bool c=((x>>i)&1); if(ch[c^1][p]) { res|=(1<<i); p=ch[c^1][p]; } else p=ch[c][p]; } return res; } void sol() { for(int i=2;i<=n;i++) b[i]=(pre[i-1]^b[1]); for(int i=1;i<=n;i++) cout<<b[i]<<' '; } signed main() { cin.tie(0); ios::sync_with_stdio(false); cin>>n; for(int i=1;i<n;i++) cin>>a[i]; for(int i=1;i<n;i++) pre[i]=(pre[i-1]^a[i]); for(int i=1;i<n;i++) ins(pre[i]); for(int i=0;i<n;i++) { int qwq=qry(i); if(qwq<=n-1) { b[1]=i; sol(); return 0; } } return 0; }

__EOF__

本文作者F x o r G
本文链接https://www.cnblogs.com/xugangfan/p/17812340.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   FxorG  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示