8.27 题解
先%一发达哥
T1,其实不难,就是一个简单的dp+矩阵快速幂加个原根优化,其实是模意义之前没做过题,有点懵,一开始思路也光想数学了,就gg了……
模意义下所有运算都和正常运算一样,只是除变成了乘逆元!!
定义状态数组f[i][j]表示第i步转移后模数为j的概率,矩阵乘优化,可得80分,正解是把每个数转化为p原根的i次方,别的都一样,会发现这样出来的是循环矩阵,复杂度降为O(logm*mod^2)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define LL long long
#define mod 1000000007
#define N 1005
using namespace std;
LL n,m,p,nn;
LL f[N],g[N],h[N],D[N],ans,pp[N],id[N],num[N];
LL qp(LL a,LL b){
LL ans=1;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;b>>=1;
}
return ans;
}
bool bo[N];
int find(int x){
for(int i=2;i<=x;i++){
memset(bo,0,sizeof bo);
int tim=0,now=1;
while(tim<x){
if(bo[now])break;
bo[now]=1; pp[tim]=now;id[now]=tim;
now=now*i%p; tim++;
}
if(tim==x-1) return i;
}
}
void mp(LL A[N],LL B[N],LL C[N]){
for(int j=0;j<p-1;j++){
D[j]=0;
for(int k=0;k<p-1;k++)
D[j]=(D[j]+A[k]*B[(j+(p-1)-k)%(p-1)])%mod;
}
for(int j=0;j<p-1;j++)C[j]=D[j];
}
int main(){
freopen("rand.in","r",stdin);
freopen("rand.out","w",stdout);
scanf("%lld%lld%lld",&n,&m,&p);
LL root=find(p);
nn=(int)qp(n,mod-2);
int a;
for(int i=1;i<=n;i++){
scanf("%d",&a);
num[id[a]]++;
}
for(int i=0;i<p-1;i++)
num[i]=num[i]*nn%mod;
f[0]=1;
for(int j=0;j<p-1;j++)
g[j]=num[j];
h[0]=1;
while(m){
if(m&1) mp(h,g,h);
mp(g,g,g); m>>=1;
}
mp(f,h,h);
for(int i=0;i<p-1;i++)
ans=(ans+h[i]*pp[i])%mod;
printf("%lld\n",ans);
return 0;
}
T2:0的情况我们可以先暴力计算出b[1],然后从b[1]出发开始dfs,由某个点的父亲的b[i]推出这个点的b[i],变化的是这个点和父亲的连边的贡献,也就是这条边两侧的点的a[i]之和的差值.
1的情况就稍微复杂一点.设以x为根的子树中所有a[i]之和为sum(x),S=
最后再来一遍dfs就好了
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define N 100050
using namespace std;
int T,n,opt;
int e=1,head[N];
int fa[N],sum[N],b[N],a[N],f[N];
long long all;
struct edge{
int u,v,next;
}ed[2*N];
void add(int u,int v){
ed[e].u=u;ed[e].v=v;
ed[e].next=head[u];
head[u]=e++;
}
void dfs1(int x){
sum[x]+=a[x];
for(int i=head[x];i;i=ed[i].next){
int v=ed[i].v;
if(v==fa[x])continue;
fa[v]=x;
dfs1(v);
sum[x]+=sum[v];b[x]+=sum[v]+b[v];
}
}
void dfs2(int x){
for(int i=head[x];i;i=ed[i].next){
int v=ed[i].v;
if(v==fa[x])continue;
b[v]=b[x]-sum[v]+(all-sum[v]);
dfs2(v);
}
}
void dfs3(int x){
f[x]=b[x]-b[fa[x]];//f[x]=all-2*sum[x]
for(int i=head[x];i;i=ed[i].next){
int v=ed[i].v;
if(v==fa[x])continue;
fa[v]=x; dfs3(v);
}
}
void dfs4(int x){
if(x==1)sum[x]=all;
else sum[x]=(all-f[x])/2;
a[x]=sum[x];
for(int i=head[x];i;i=ed[i].next){
int v=ed[i].v;
if(v==fa[x])continue;
dfs4(v);
a[x]-=sum[v];
}
}
void init(){
e=1;all=0;
memset(head,0,sizeof head);
memset(fa,0,sizeof fa);
memset(sum,0,sizeof sum);
memset(a,0,sizeof a);
memset(b,0,sizeof b);
memset(f,0,sizeof f);
}
int main(){
scanf("%d",&T);
while(T--){
init();
scanf("%d",&n); int u,v;
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
scanf("%d",&opt);
if(opt==0){
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
all+=a[i];
}
dfs1(1); dfs2(1);
for(int i=1;i<=n;i++)printf("%d ",b[i]);
printf("\n");
}
if(opt==1){
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
dfs3(1);
for(int i=2;i<=n;i++) all+=f[i];
all+=2*b[1]; all/=(n-1);
dfs4(1);
for(int i=1;i<=n;i++)printf("%d ",a[i]);
printf("\n");
}
}
return 0;
}
T3,组合数,卡特兰数,dp杂糅
opt=0:枚举横向移动了多少步.横向移动i步时方案数为
opt=1:纯卡特兰数
opt=2:f[i]表示走了i步回到原点的方案数,枚举第一次回到原点时走过的步数j,则此时方案数为
opt=3:依然枚举横向移动了多少步.横向移动i步时,方案数为
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define mod 1000000007
#define N 100050
#define LL long long
using namespace std;
LL fac[2*N],ans,now,f[1050];
int n,opt;
LL qp(LL a,LL b){
LL ans=1;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;b>>=1;
}
return ans;
}
LL C(int a,int b){
if(!b||b==a)return 1;
if(b>a)return 0;
return (fac[a]*qp(fac[a-b],mod-2)%mod)*qp(fac[b],mod-2)%mod;
}
LL cal(int x){
if(x<=0)return 1;
return C(2*x,x)*qp(x+1,mod-2)%mod;
}
int main(){
scanf("%d%d",&n,&opt);
if(n&1){printf("0\n");return 0;}
fac[1]=1;
for(int i=2;i<=2*n;i++)fac[i]=fac[i-1]*i%mod;
if(opt==0){
for(int i=0;i<=n;i+=2){
now=(C(n,i)*C(i,i>>1)%mod)*C((n-i),(n-i)>>1)%mod;
ans=(ans+now)%mod;
}
printf("%lld\n",ans);
return 0;
}
if(opt==1){
ans=cal(n>>1);
printf("%lld\n",ans);
}
if(opt==2){
f[0]=1;
for(int i=2;i<=n;i+=2)
for(int j=0;j<=i;j+=2)
f[i]=(f[i]+4*f[i-j]*cal((j>>1)-1))%mod;
printf("%lld\n",f[n]);
}
if(opt==3){
for(int i=0;i<=n;i+=2){
now=C(n,i)*cal(i>>1)%mod*cal((n-i)>>1)%mod;
ans=(ans+now)%mod;
}
printf("%lld\n",ans);
}
return 0;
}
再贴个考试时65分的傻暴力
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define mod 1000000007
using namespace std;
int n,opt;
long long f[2][2050][2050];
int main(){
scanf("%d%d",&n,&opt);
if(n&1){
printf("0\n");
return 0;
}
if(opt==0){
int ii=0;
f[ii][n+1][n+1]=1;
for(int i=1;i<=n;i++){
ii^=1;
for(int j=1;j<=2*n+2;j++)
for(int k=1;k<=2*n+2;k++)
if(f[ii^1][j][k]){
f[ii][j+1][k]=(f[ii][j+1][k]+f[ii^1][j][k])%mod;
f[ii][j-1][k]=(f[ii][j-1][k]+f[ii^1][j][k])%mod;
f[ii][j][k+1]=(f[ii][j][k+1]+f[ii^1][j][k])%mod;
f[ii][j][k-1]=(f[ii][j][k-1]+f[ii^1][j][k])%mod;
f[ii^1][j][k]=0;
}
}
printf("%lld\n",f[ii][n+1][n+1]);
}
if(opt==1){
int ii=0;
f[ii][n+1][n+1]=1;
for(int i=1;i<=n;i++){
ii^=1;
for(int j=n;j<=2*n+2;j++)
for(int k=n+1;k<n+2;k++)
if(f[ii^1][j][k]){
f[ii][j+1][k]=(f[ii][j+1][k]+f[ii^1][j][k])%mod;
if(j-1>=n+1)
f[ii][j-1][k]=(f[ii][j-1][k]+f[ii^1][j][k])%mod;
f[ii^1][j][k]=0;
}
}
printf("%lld\n",f[ii][n+1][n+1]);
}
if(opt==2){
int ii=0;
f[ii][n+1][n+1]=1;
for(int i=1;i<=n;i++){
ii^=1;
for(int j=1;j<=2*n+2;j++)
for(int k=n+1;k<n+2;k++)
{
if(j==n+1&&k==n+1)continue;
if(f[ii^1][j][k]){
f[ii][j+1][k]=(f[ii][j+1][k]+f[ii^1][j][k])%mod;
f[ii][j-1][k]=(f[ii][j-1][k]+f[ii^1][j][k])%mod;
f[ii^1][j][k]=0;
}
}
for(int j=n+1;j<n+2;j++)
for(int k=1;k<=2*n+2;k++)
{
if(j==n+1&&k==n+1)continue;
if(f[ii^1][j][k]){
f[ii][j][k+1]=(f[ii][j][k+1]+f[ii^1][j][k])%mod;
f[ii][j][k-1]=(f[ii][j][k-1]+f[ii^1][j][k])%mod;
f[ii^1][j][k]=0;
}
}
for(int j=n+1;j<n+2;j++)
for(int k=n+1;k<n+2;k++)
if(f[ii^1][j][k]){
f[ii][j+1][k]=(f[ii][j+1][k]+f[ii^1][j][k])%mod;
f[ii][j-1][k]=(f[ii][j-1][k]+f[ii^1][j][k])%mod;
f[ii][j][k+1]=(f[ii][j][k+1]+f[ii^1][j][k])%mod;
f[ii][j][k-1]=(f[ii][j][k-1]+f[ii^1][j][k])%mod;
f[ii^1][j][k]=0;
}
}
printf("%lld\n",f[ii][n+1][n+1]);
}
if(opt==3){
int ii=0;
f[ii][n+1][n+1]=1;
for(int i=1;i<=n;i++){
ii^=1;
for(int j=n+1;j<=2*n+2;j++)
for(int k=n+1;k<=2*n+2;k++)
if(f[ii^1][j][k]){
f[ii][j+1][k]=(f[ii][j+1][k]+f[ii^1][j][k])%mod;
f[ii][j-1][k]=(f[ii][j-1][k]+f[ii^1][j][k])%mod;
f[ii][j][k+1]=(f[ii][j][k+1]+f[ii^1][j][k])%mod;
f[ii][j][k-1]=(f[ii][j][k-1]+f[ii^1][j][k])%mod;
f[ii^1][j][k]=0;
}
}
printf("%lld\n",f[ii][n+1][n+1]);
}
return 0;
}
人生如梦亦如幻 朝如晨露暮如霞。