Codeforces Round #539 div1
1109A. Sasha and a Bit of Relax
记 $sum[i]$ 表示前 $i$ 位的异或和,当一个 $l,r$ 可以作为答案即 $sum[l]==sum[r]$ 并且 $l,r$ 同奇偶,所以我们可以记 $v[i][0/1]$ 表示前缀异或值为 $i$ 并且所在位置为奇/偶的方案数。每位答案为在我之前前缀异或值和我相同所在位置和我同奇偶的方案数。
效率 $O(n)$
以下代码:
#include<bits/stdc++.h> #define il inline #define LL long long #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=3e5+5,M=2e6; LL ans; int n,a[N],v[M][2],sum; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } int main() { n=read();v[0][0]++; for(int i=1;i<=n;i++){ a[i]=read();sum^=a[i]; ans+=v[sum][i&1]; v[sum][i&1]++; } printf("%I64d\n",ans); return 0; }
1109B. Sasha and One More Name
对于一个长度为 $n$ 的回文串,只有当相同字母数 $\le n-1$ 时,才一定存在答案。否则一定无解。
考虑什么时候会有答案为 $1$ :
切一刀变成回文串,相当于把这个串结成一个环,如果从一个地方切下一刀形成的链得到与原串不相同的回文串,那么切一刀合法。
剩余的所有情况,因为我们保证回文串一定在对称的部分存在不同字母,那么一定存在一种情况在两边对称的地方切一刀,左右交换,得到新的回文串。
以下代码:
#include<bits/stdc++.h> #define il inline #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=5005; char s[N<<1];int n; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } il bool pd0(){ int mid=n>>1; for(int i=1;i<mid;i++){ if(s[i]!=s[i+1])return 1; } mid++;if(n&1)mid++; for(int i=mid;i<n;i++){ if(s[i]!=s[i+1])return 1; } return 0; } il bool pd(int l){ int mid=n>>1; for(int i=1;i<=mid;i++){ int j=l+n-i; if(s[l+i-1]!=s[j])return 0; } for(int i=1;i<=n;i++)if(s[i]!=s[i+l-1])return 1; return 0; } il bool pd1(){ for(int i=2;i<=n;i++){ if(pd(i))return 1; } return 0; } int main() { scanf(" %s",s+1);n=strlen(s+1); for(int i=1;i<=n;i++)s[i+n]=s[i]; if(n<=3||!pd0())return puts("Impossible"),0; if(pd1())return puts("1"),0; puts("2"); return 0; }
1109D. Sasha and Interesting Fact from Graph Theory
测试的时候看错题目了气哭!
考虑枚举在 $a,b$ 之间点的个数。
$$
ans=\sum_{i=0}^{min(m-1,n-2)}C_{n-2}^{i}i!C_{m-1}^{i}(i+2)n^{n-i-3}m^{n-i-2}
$$
$C_{n-2}^{i}$ 表示在除 $a,b$ 外的点中选出 $i$ 个点作为 $a,b$ 链上的点
$i!$ 表示 $a,b$ 之间的点的排列顺序
$C_{m-1}^{i}$ 表示 $a,b$ 链之间的点的长度分布(插板法)
$(i+2)n^{n-i-3}$ 表示不在链上的点的分布的方案数(根据 $Cayley$ 公式)
$m^{n-i-2}$ 表示不在链上每个点连接的边不同长度的方案数
以下代码:
#include<bits/stdc++.h> #define il inline #define LL long long #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=1e6+5,p=1e9+7; int n,m,jc[N],ny[N],ans,po[N],M[N],mx; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } il int ksm(LL a,int y){ LL b=1; while(y){ if(y&1)b=b*a%p; a=a*a%p;y>>=1; } return b; } il int mu(int x,int y){ return (x+y>=p)?x+y-p:x+y; } il int C(int n,int m){ return 1ll*jc[n]*ny[m]%p*ny[n-m]%p; } int main() { n=read();m=read();read();read();mx=max(n,m); jc[0]=1;for(int i=1;i<=mx;i++)jc[i]=1ll*i*jc[i-1]%p; ny[mx]=ksm(jc[mx],p-2);for(int i=mx;i;i--)ny[i-1]=1ll*i*ny[i]%p; po[0]=1;for(int i=1;i<=mx;i++)po[i]=1ll*n*po[i-1]%p; M[0]=1;for(int i=1;i<=mx;i++)M[i]=1ll*m*M[i-1]%p; for(int i=0;i<=min(m-1,n-2);i++){ if(i==n-2)ans=mu(ans,1ll*C(m-1,i)*jc[i]%p); else ans=mu(ans,1ll*C(n-2,i)*jc[i]%p*C(m-1,i)%p*(i+2)%p*po[n-i-3]%p*M[n-i-2]%p); } printf("%d\n",ans); return 0; }
1109E. Sasha and a Very Easy Test
#include<bits/stdc++.h> #define il inline #define LL long long #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=1e5+5; int n,p,b[12],t,f,c[N]; il int ksm(LL a,int y){ LL b=1; while(y){ if(y&1)b=b*a%p; a=a*a%p;y>>=1; } return b; } struct node{ int s,r,a[12],d; void clear(){ for(int i=1;i<=t;i++)a[i]=0; r=d=1; } void operator+=(node x){ for(int i=1;i<=t;i++)a[i]+=x.a[i]; r=1ll*r*x.r%p;s=1ll*s*x.d%p;d=1ll*d*x.d%p; } void operator-=(node x){ r=1ll*r*ksm(x.r,f-1)%p;s=r; for(int i=1;i<=t;i++)a[i]-=x.a[i],s=1ll*s*ksm(b[i],a[i])%p; d=s; } void operator^=(int x){ clear();s=d=x%p; for(int i=1;i<=t;i++){ while(!(x%b[i]))a[i]++,x/=b[i]; } r=x%p; } }val[N<<2],d; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } il int mu(int x,int y){ return (x+y>=p)?x+y-p:x+y; } il void update(int x){ val[x].s=mu(val[x<<1].s,val[x<<1|1].s); } il void pushdown(int x){ if(val[x].d==1)return; val[x<<1]+=val[x]; val[x<<1|1]+=val[x]; val[x].clear(); } il void build(int x,int l,int r){ if(l==r){val[x]^=c[l];return;} int mid=(l+r)>>1;val[x].clear(); build(x<<1,l,mid);build(x<<1|1,mid+1,r); update(x); } il void mul(int x,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr){val[x]+=d;return;} int mid=(l+r)>>1;pushdown(x); if(ql<=mid)mul(x<<1,l,mid,ql,qr); if(mid<qr)mul(x<<1|1,mid+1,r,ql,qr); update(x); } il void div(int x,int l,int r,int pos){ if(l==r){val[x]-=d;return;} int mid=(l+r)>>1;pushdown(x); if(pos<=mid)div(x<<1,l,mid,pos); else div(x<<1|1,mid+1,r,pos); update(x); } il int query(int x,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr)return val[x].s; int mid=(l+r)>>1;pushdown(x); int res=0; if(ql<=mid)res=query(x<<1,l,mid,ql,qr); if(mid<qr)res=mu(res,query(x<<1|1,mid+1,r,ql,qr)); return res; } int main() { n=read();p=read();int tmp=p; for(int i=2;i*i<=tmp;i++){ if(!(tmp%i)){ b[++t]=i; while(!(tmp%i))tmp/=i; } } if(tmp>1)b[++t]=tmp;f=p; for(int i=1;i<=t;i++)f-=f/b[i]; for(int i=1;i<=n;i++)c[i]=read(); build(1,1,n);int Q=read(); while(Q--){ int op=read(); if(op==1){ int x=read(),y=read(),z=read(); d^=z;mul(1,1,n,x,y); } else if(op==2){ int x=read(),z=read(); d^=z;div(1,1,n,x); } else{ int x=read(),y=read(); printf("%d\n",query(1,1,n,x,y)); } } return 0; }