zoukankan      html  css  js  c++  java
  • AGC005D ~K Perm Counting

    题意

    求长度为(n),不存在(leftvert a_i-i ightvert=k)的排列个数
    (n le 2000)
    传送门

    思路

    正着来并不是很好做,于是考虑反着做。
    发现如果把限制条件连起来,会变成多条链
    例如=考虑(n=7,k=2)会有这样(4)条链:
    ((1, otoperatorname{3},5, otoperatorname{7}))
    ((2, otoperatorname{4},6))
    (( otoperatorname{1},3, otoperatorname{5},7))
    (( otoperatorname{2},4, otoperatorname{6}))
    只要链前后的两个数连在一起,就会产生不合法的数对
    容斥(f[i][j][0/1])表示在第(i)位,有(j)个数满足(leftvert a_i-i ightvert=k),当前数与前面的有没有连
    对于单条的链,(dp)方程还是很显然的:

    • 这个数与后面的连起来(必须保证前面和它没连):(f[i][j][1]+=f[i-1][j-1][0])
    • 不连:(f[i][j][0]+=f[i-1][j][1]+f[i-1][j][0])

    那么考虑多条链怎么合并,其实就是链末端往后面连不会有贡献,所以就可以把所有链拼成一条链,(f[链末][j][1])是不可能存在的。只要刚开始做好标记,按照一条链的来做就完成了。
    最后容斥即可。

    #include <bits/stdc++.h>
    const int mu=924844033;
    int n,k,f[2][4005][2],cnt,p[2005],a[4005],now,ans;
    int main(){
    	scanf("%d%d",&n,&k);
    	p[0]=1;
    	for(int i=1;i<=n;i++) p[i]=p[i-1]*1ll*i%mu;
    	for (int i=1;i<=k;i++){
    		a[cnt]=-1;
    		for(int j=i;j<=n;j+=k) cnt++;
    		a[cnt]=-1;
    		for(int j=i;j<=n;j+=k) cnt++;
    	}
    	now=1,f[now][0][0]=1;
    	for (int i=1;i<cnt;i++){
    		now=now^1;
    		memset(f[now],0,sizeof(f[now]));
    		for (int j=0;j<=i;j++){
    			f[now][j][0]=(f[now][j][0]+f[now^1][j][1]+f[now^1][j][0])%mu;
    			if (j && !a[i]) f[now][j][1]=(f[now][j][1]+f[now^1][j-1][0])%mu;
    		}
    	}
    	ans=p[n];
    	for (int i=1;i<=n;i++){
    		ans=(ans+(f[now][i][0]+f[now][i][1])*(i&1?-1:1)*1ll*p[n-i]%mu+mu)%mu;
    	}
    	printf("%d
    ",ans);
    }
    

    后记

    想不到的神仙(dp),好短啊。我好菜啊

  • 相关阅读:
    sql语句中的一些常用语法
    torch_12_BigGAN全文解读
    torch_12_dataset和dataLoader,Batchnormalization解读
    torch_11_BEGAN
    torch_11_风格迁移和cycleGAN
    torch_10_stackGAN-V2
    torch_09_DCGAN_注意的细节
    torch_09_GAN
    pytorch-04-激活函数
    torch_07_卷积神经网络案例分析
  • 原文地址:https://www.cnblogs.com/flyfeather6/p/11904209.html
Copyright © 2011-2022 走看看