Codeforces Round #736 (Div. 2) 题解
比赛地址:https://codeforces.com/contest/1549。
只有 ABCDE 的题解,F1F2 不会。
A
由于 \(P\) 是奇数,所以只需让 \(a=2,b=\frac{P-1}2\) 即可。
typedef long long ll;
void mian(){
int P;scanf("%d",&P);
P--;
if(P==4)printf("%d %d\n",2,4);
else printf("%d %d\n",2,P/2);
}
B
能放就放即可。
typedef long long ll;
const int N=2e5;
int n,a[N+10],b[N+10],vis[N+10];
void mian(){
for(int i=1;i<=n;i++)a[i]=b[i]=vis[i]=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%1d",&a[i]);
for(int i=1;i<=n;i++)scanf("%1d",&b[i]);
int ans=0;
for(int i=1;i<=n;i++){
if(b[i]==1){
if(a[i-1]==1&&!vis[i-1]){vis[i-1]=1;ans++;}
else if(a[i]==0&&!vis[i]){vis[i]=1;ans++;}
else if(a[i+1]==1&&!vis[i+1]){vis[i+1]=1;ans++;}
}
}
printf("%d\n",ans);
}
C
把这些关系想成是一个有向图,边都是从编号小的点连到编号大的点。
那么,如果一个点有出度,这个点就要 GG。
维护一下每个点的出度即可。
typedef long long ll;
const int N=2e5;
int n,m,q,ans,outd[N+10];
void mian(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int u,v;scanf("%d%d",&u,&v);
if(u>v)std::swap(u,v);
outd[u]++;
}
ans=n;
for(int i=1;i<=n;i++)
if(outd[i]>=1)ans--;
scanf("%d",&q);
while(q--){
int opt,u,v;scanf("%d",&opt);
if(opt==1){
scanf("%d%d",&u,&v);
if(u>v)std::swap(u,v);
outd[u]++;
if(outd[u]==1)ans--;
}
if(opt==2){
scanf("%d%d",&u,&v);
if(u>v)std::swap(u,v);
outd[u]--;
if(outd[u]==0)ans++;
}
if(opt==3)printf("%d\n",ans);
}
}
D
如果一个数组是合法的,那么这个数组的差分数组的 \(\gcd\) 要 \(\gt 1\)。
先求出 \(a\) 的差分数组 \(d\)。对于每个 \(l\in[1,n-1]\),我们要找到最大的 \(r\),使得 \(\gcd_{i=l}^rd_i\gt 1\)。
倍增实现即可。
typedef long long ll;
const int N=2e5;
const int LOGN=20;
int n;
ll a[N+10],d[N+10],f[N+10][LOGN+5];
ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}
void mian(){
for(int i=1;i<=n+1;i++){
a[i]=d[i]=0;
for(int j=0;j<=LOGN;j++)
f[i][j]=0;
}
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",a+i);
for(int i=1;i<=n;i++)
d[i]=std::abs(a[i+1]-a[i]),f[i][0]=d[i];
for(int j=1;j<=LOGN;j++)
for(int i=1;i+(1<<(j-1))<=n;i++)
f[i][j]=gcd(f[i][j-1],f[i+(1<<(j-1))][j-1]);
int ans=1;
for(int i=1;i<=n;i++){
ll now=d[i];
int r=i;
if(now<=1)continue;
for(int j=LOGN;~j;j--)
if(r+(1<<j)<=n&&f[r][j]>1&&gcd(now,f[r][j])>1)now=gcd(now,f[r][j]),r+=(1<<j);
ans=std::max(ans,r-i+1);
}
printf("%d\n",ans);
}
E
题目相当于让我们求:
\[\sum_{i=0}^n\binom{3i}x
\]
考虑用 dp 求出这个式子。设:
\[f_{x,j}=\sum_{i=0}^n\binom{3i+j}x,0\le j\le 2
\]
那么答案就是 \(f_{x,0}\)。
我们运用公式 \(\binom nm=\binom{n-1}m+\binom{n-1}{m-1}\),可以推出 \(f_{x,1},f_{x,2}\) 的转移方程:
\[f_{x,j}=\sum_{i=0}^n\binom{3i+j}x=\sum_{i=0}^n\binom{3i+j-1}x+\sum_{i=0}^n\binom{3i+j-1}{x-1}=f_{x,j-1}+f_{x-1,j-1},1\le j\le 2
\]
我们运用公式 \(\sum_{i=0}^n\binom ix=\binom{n+1}{x+1}\),可以推出 \(f_{x,0}\) 的转移方程:
\[f_{x,0}=(f_{x,0}+f_{x,1}+f_{x,2})-f_{x,1}-f_{x,2}=\sum_{i=0}^{3n+2}\binom ix-f_{x,1}-f_{x,2}=\binom{3n+3}{x+1}-f_{x,1}-f_{x,2}
\]
于是,我们得到了一个方程组:
\[\begin{cases}
f_{x,0}=\binom{3n+3}{x+1}-f_{x,1}-f_{x,2}\\
f_{x,1}=f_{x,0}+f_{x-1,0}\\
f_{x,2}=f_{x,1}+f_{x-1,1}
\end{cases}
\]
解得:
\[\begin{cases}
f_{x,0}=\dfrac{\binom{3n+3}{x+1}-2f_{x-1,0}-f_{x-1,1}}{3}\\
f_{x,1}=f_{x,0}+f_{x-1,0}\\
f_{x,2}=f_{x,1}+f_{x-1,1}
\end{cases}
\]
边界:\(f_{0,0}=f_{0,1}=f_{0,2}=n+1\)。
typedef long long ll;
const int N=1e6;
const int P=1e9+7;
int n,m,f[N*3+10][3];
int fac[N*3+10],ifac[N*3+10];
inline int qpow(int a,int b,int p){
int res=1;
while(b){if(b&1)res=1LL*res*a%p;a=1LL*a*a%p;b>>=1;}
return res;
}
inline int inv(int a,int p){return qpow(a,p-2,p);}
void initComb(int p){
int lim=std::min(n*3+5,p-1);
fac[0]=1;for(int i=1;i<=lim;i++)fac[i]=1LL*fac[i-1]*i%p;
ifac[lim]=inv(fac[lim],p);for(int i=lim-1;i>=0;i--)ifac[i]=1LL*ifac[i+1]*(i+1)%p;
}
inline int C(int a,int b,int p){if(a<b)return 0;else return 1LL*fac[a]*ifac[b]%p*ifac[a-b]%p;}
void mian(){
scanf("%d%d",&n,&m);
initComb(P);
f[0][0]=f[0][1]=f[0][2]=n+1;
int inv3=inv(3,P);
for(int i=1;i<=n*3;i++){
f[i][0]=1LL*(((C(3*n+3,i+1,P)-2*f[i-1][0]%P-f[i-1][1])%P+P)%P)*inv3%P;
f[i][1]=(f[i][0]+f[i-1][0])%P;
f[i][2]=(f[i][1]+f[i-1][1])%P;
}
while(m--){
int x;scanf("%d",&x);
printf("%d\n",f[x][0]);
}
}
本文来自博客园,作者:registerGen,转载请注明原文链接:https://www.cnblogs.com/registergen/p/cf_round_736_solution.html