前言
- 最近考试考得最差的一次吧。
- 考试的时候太浮躁了,T2题都读错。
- 其实读错题没什么,主要是T1连对拍都不打,于是一些非常智障的错误导致本应AC的代码变成WA0。
- 以后考试有时间的话对拍还是尽量题题都打……
T1
- 这场考试也挺奇怪的,我感觉T1应该是三个题里最难的。
- 考试的时候刚开始一直觉得直接快速幂就行,但后来发现需要考虑行间关系,便很自然的想到正解。
- 可以把%n后结果相同的列一起考虑,这样可以进行dp
- 设f[i][j]表示考虑了%n结果不大于i的所有列,一共放了j个棋子的方案数。
- 则$f[i][j]=\sum\limits_{k=max(0,j-n)}^j f[i-1][j-k]*{{C_n^k}^{m/n+[m\%n>=i]}}$
- 显然可以滚动。
- 然后我就滚动不清空,爆零两行泪了……
- ${C_n^k}^{m/n+[m\%n>=i]}$这个东西可以预处理的。
- 所以时间复杂度为$\Theta(N^4)$,空间复杂度$\Theta(N^2)$。
- 注意有(应该有,我不确定)m<n的情况。
#include<cstdio> using namespace std; int const N=10002,M=102,mod=1e9+7; long long fac[N],inv[N]; long long cp[M]; long long f[2][N]; int cf[M]; long long cq[M][2]; inline long long power(long long x,long long y){ long long ans=1; for(;y;y>>=1,x=x*x%mod) if(y&1)ans=ans*x%mod; return ans; } inline long long C(int x,int y){ return fac[x]*inv[y]%mod*inv[x-y]%mod; } inline int max(int x,int y){ return x>y?x:y; } int main(){ //freopen("3.in","r",stdin); //freopen("6.out","w",stdout); int n,c; long long m; scanf("%d%lld%d",&n,&m,&c); int lit=n*n,hh=m%n,pc=(m/n)%(mod-1); fac[0]=1; for(register int i=1;i<=lit;++i)fac[i]=fac[i-1]*i%mod; inv[lit]=power(fac[lit],mod-2); for(register int i=lit;i;--i)inv[i-1]=inv[i]*i%mod; for(register int i=0;i<=n;++i)cp[i]=C(n,i); for(register int i=1;i<=hh;++i)cf[i]=1; for(register int i=0;i<=n;++i) cq[i][0]=power(cp[i],pc),cq[i][1]=cq[i][0]*cp[i]%mod; int u=0,v=1; f[0][0]=1; if(m<n){ for(register int i=1;i<=m;++i,u=v,v^=1) for(register int j=0;j<=c;++j){ f[v][j]=0; for(register int k=max(0,j-n);k<=j;++k) f[v][j]=(f[v][j]+cq[j-k][1]*f[u][k])%mod; } printf("%lld",f[u][c]); return 0; } for(register int i=1;i<=n;++i,u=v,v^=1) for(register int j=0;j<=c;++j){ f[v][j]=0; for(register int k=max(0,j-n);k<=j;++k) f[v][j]=(f[v][j]+cq[j-k][cf[i]]*f[u][k])%mod; } printf("%lld",f[u][c]); return 0; }