T1:对于加法用前缀和sumi表示第i个数,对于修改,直接将sumi的值改为修改后的值。
如果查询的区间[l,r]内有修改操作,那么就输出sumr,否则输出sumr-suml-1.
注意需按题目要求解码,同时用long long存储部分数据。
Code:
1 #include<iostream> 2 #include<cstdio> 3 #define MN 10000005 4 #define ll long long 5 #define mod 998244353 6 using namespace std; 7 unsigned int seed,a[MN]; 8 int n,m,l[MN],r[MN],ans=0,sum[MN],pos[MN],pwr=1; 9 bool type[MN]; 10 unsigned int GetNext(){ 11 seed^=(seed<<7);seed^=(seed>>8);seed^=(seed<<13); 12 return seed; 13 } 14 int main() 15 { 16 scanf("%d%d%u",&n,&m,&seed);sum[0]=pos[0]=0; 17 for (int i=1;i<=n;++i) type[i]=GetNext()%2,a[i]=GetNext(); 18 for (int i=1;i<=n;++i){ 19 if (!type[i]) sum[i]=(1ll*sum[i-1]+(1ll*a[i])%mod)%mod,pos[i]=pos[i-1]; 20 else pos[i]=i,sum[i]=(1ll*a[i])%mod; 21 }for (int i=1;i<=m;++i){ 22 l[i]=GetNext()%n+1,r[i]=GetNext()%n+1;int tmp; 23 if(l[i]>r[i]) tmp=l[i],l[i]=r[i],r[i]=tmp; 24 ll res=0ll;pwr=(233ll*pwr)%mod; 25 res=(l[i]<=pos[r[i]]?sum[r[i]]:sum[r[i]]-sum[l[i]-1]); 26 if (res<0) res+=mod;ans=(1ll*ans+(1ll*pwr*res)%mod)%mod; 27 }cout<<ans;return 0; 28 }
T2:可知若两个字符串的最小表示相同,那么它们循环同构。
对每个字符串求其最小表示,将其最小表示插入trie树中。时间复杂度O(nm).
亦可用字符串hash通过此题。
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define MN 1000005 5 using namespace std; 6 inline int in(){ 7 int x=0;bool f=0; char c; 8 for (;(c=getchar())<'0'||c>'9';f=c=='-'); 9 for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0'); 10 return f?-x:x; 11 } 12 char s[MN<<1]; 13 int f[MN][26],v[MN],n,m,pos,u,cnt=0; 14 long long ans=0ll; 15 inline int expr(){ 16 int i=0,j=1;while (i<m&&j<m){ 17 int k=0; 18 while (s[i+k]==s[j+k]&&k<m-1) ++k; 19 if (s[i+k]<s[j+k]) j+=k+1;else i+=k+1; 20 if (i==j) ++j; 21 }return i<j?i:j; 22 } 23 int main() 24 { 25 n=in();m=in();for (int i=1;i<=n;++i){ 26 scanf("%s",s);for (int j=0;j<=m;++j) s[j+m]=s[j]; 27 pos=expr();u=1; 28 for (int i=0;i<m;++i){ 29 if (!f[u][s[pos+i]-'a']) f[u][s[pos+i]-'a']=(++cnt); 30 u=f[u][s[pos+i]-'a']; 31 }ans+=1ll*v[u];++v[u]; 32 }printf("%lld",ans);return 0; 33 }
T3:树形dp.
易知答案为叶子节点中的一个值。从大到小考虑每个数字,将大于或等于该数字k的数字认为是合法的。
f[i]表示i的能量值v[i]合法时最少需要填充的数字个数。
对于叶子节点i不能被交换时,v[i]合法,则f[i]=0,否则f[i]=inf.对于i可以被交换时,f[i]=1.
对于非叶结点i,v[i]等于i的三个儿子中f值较小的两个儿子的f[i]值之和。判断f[1]是否超过m即可。
易知k值越小时f值越小,合法的数字越多,具有单调性。考虑二分答案。时间复杂度O(n log n).
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define MN 1000005 5 #define inf 1000000000 6 using namespace std; 7 inline int in(){ 8 int x=0;bool f=0; char c; 9 for (;(c=getchar())<'0'||c>'9';f=c=='-'); 10 for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0'); 11 return f?-x:x; 12 } 13 int f[MN][3],val[MN],st[MN],n,m,x,cnt=0,ans; 14 bool tr[MN]; 15 inline int dp(int u,int v){ 16 if (f[u][0]==-1) return tr[u]?1:(val[u]>=v?0:inf); 17 else { 18 int sum[3];memset(sum,0,sizeof(sum)); 19 for (int i=0;i<3;++i) sum[i]=dp(f[u][i],v); 20 sort(sum,sum+3);return min(n+1,sum[0]+sum[1]); 21 } 22 } 23 int main() 24 { 25 n=in();m=in();for (int i=1;i<=n;++i){ 26 f[i][0]=in();if (f[i][0]==-1) val[i]=in(); 27 else f[i][1]=in(),f[i][2]=in(); 28 }for (int i=1;i<=m;++i){ 29 x=in();tr[x]=1;st[++cnt]=val[x]; 30 }sort(st+1,st+cnt+1);int l=1,r=inf; 31 while (l<=r){ 32 int mid=(l+r)>>1; 33 if (dp(1,mid)<=cnt-(lower_bound(st+1,st+cnt+1,mid)-st)+1) 34 ans=mid,l=mid+1;else r=mid-1; 35 }printf("%d",ans);return 0; 36 }