清北模拟题4
Posted 蒟蒻sjy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了清北模拟题4相关的知识,希望对你有一定的参考价值。
更正:第三组:不存在相同的字符|str|=26,26<=n<=100
题解:kmp+矩阵乘法(类似 GT算法,只需将 GT算法的代码(ps:GT算法是一道题)进行一下修改)。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define MAXN 10100 #define MAXM 110 #define M 1000000007 using namespace std; int dp[MAXN][MAXM]; int fail[MAXM]; int trs[MAXN][26]; char str[MAXN]; void xx(int &x,int y) { x+=y; if (x>=M) x-=M; } int main() { int n; while (~scanf("%d%s",&n,str+1)) { memset(dp,0,sizeof(dp)); int m=strlen(str+1); fail[1]=0; for (int i=2;i<=m;i++) { int p=fail[i-1]; while (p && str[p+1]!=str[i]) p=fail[p]; if (str[p+1]==str[i]) fail[i]=p+1; } memset(trs,-1,sizeof(trs)); memset(trs[0],0,sizeof(trs[0])); for (int i=0;i<m;i++) trs[i][str[i+1]-\'a\']=i+1; for (int i=0;i<=m;i++) for (int j=0;j<26;j++) if (trs[i][j]==-1) trs[i][j]=trs[fail[i]][j]; dp[0][0]=1; for (int i=0;i<n;i++) for (int j=0;j<m;j++) for (int k=0;k<26;k++) xx(dp[i+1][trs[j][k]],dp[i][j]); long long ans=0; long long x=1; for (int i=n;i>=0;i--) { ans = (ans+x*dp[i][m])%M; if (i)x=x*26%M; } printf("%d\\n",(int)((x-ans)%M+M)%M); } }
更正:输出的顺序保证a<b
更正:输出样例:0 1000000006
题解:类似斐波那契数列,进行一下变形。加上矩阵乘法。(数据很大)
#include<cstdio> #include<iostream> #define M 1000000007 using namespace std; long long b[3][3],c[3][3],ans[3][3]; long long n; void work(long long n) { b[1][1]=ans[1][1]=0; b[1][2]=ans[1][2]=1; b[2][1]=ans[2][1]=1; b[2][2]=ans[2][2]=1; while(n) { if(n&1) { for(int k=1;k<=2;k++) for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) c[i][j]=(c[i][j]+(ans[i][k]%M*b[k][j]%M))%M; for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) ans[i][j]=c[i][j],c[i][j]=0; } for(int k=1;k<=2;k++) for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) c[i][j]=(c[i][j]+(b[i][k]%M*b[k][j]%M))%M; for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) b[i][j]=c[i][j],c[i][j]=0; n/=2; } long long ans1=(ans[1][2])%M,ans2=(ans[1][1]+ans[1][2])%M; cout<<min(ans1,ans2)<<" "<<max(ans1,ans2); } int main() { cin>>n; work(n); return 0; }
更正:模数1000000007
题解:考试的时候这个题全部爆零。当时以为是二分图匹配的题,结果是树形dp,被题目坑了一把。
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #define maxn 100010 #define mod 1000000007 #define ll long long using namespace std; ll T,P,n,head[maxn],num,f[maxn][2],g[maxn][2],L,R[maxn],l,r[maxn],son[maxn]; struct node { ll v,pre; }e[maxn*2]; void Add(ll from,ll to) { num++;e[num].v=to; e[num].pre=head[from]; head[from]=num; } void xx() { num=0; memset(f,0,sizeof(f)); memset(g,0,sizeof(g)); memset(head,0,sizeof(head)); } void DP(ll now,ll from) { g[now][0]=1; ll mx,sum; for(int i=head[now];i;i=e[i].pre) { ll v=e[i].v; if(v==from)continue; DP(v,now); mx=max(f[v][1],f[v][0]);sum=0; if(mx==f[v][1])sum+=g[v][1]; if(mx==f[v][0])sum+=g[v][0]; g[now][0]=g[now][0]*sum%mod; f[now][0]+=mx; } L=0;l=1;ll S=0; for(int i=head[now];i;i=e[i].pre) if(e[i].v!=from)son[++S]=e[i].v; R[S+1]=0; r[S+1]=1; for(int i=S;i>=1;i--) { ll v=son[i];sum=0; mx=max(f[v][1],f[v][0]); if(mx==f[v][1])sum+=g[v][1]; if(mx==f[v][0])sum+=g[v][0]; R[i]=R[i+1]+mx; r[i]=r[i+1]*sum%mod; } for(int i=1;i<=S;i++) { ll v=son[i]; mx=L+f[v][0]+R[i+1]+1; if(mx>f[now][1]) { f[now][1]=mx; g[now][1]=l*g[v][0]%mod*r[i+1]%mod; } else if(mx==f[now][1]) g[now][1]=(g[now][1]+l*g[v][0]%mod*r[i+1]%mod)%mod; sum=0; mx=max(f[v][1],f[v][0]); if(mx==f[v][1])sum+=g[v][1]; if(mx==f[v][0])sum+=g[v][0]; l=l*sum%mod; L+=mx; } } int main() { cin>>T>>P; while(T--) { cin>>n; ll u,v; xx(); for(int i=1;i<n;i++) { cin>>u>>v; Add(u,v); Add(v,u); } DP(1,0); ll sum,mx; mx=max(f[1][0],f[1][1]); sum=0; if(mx==f[1][0]) sum+=g[1][0],sum%=mod; if(mx==f[1][1]) sum+=g[1][1],sum%=mod; if(P==1) cout<<mx<<endl; if(P==2) cout<<mx<<" "<<sum<<endl; } return 0; }
以上是关于清北模拟题4的主要内容,如果未能解决你的问题,请参考以下文章