zoukankan      html  css  js  c++  java
  • 【ARC102E】Stop. Otherwise...

    题目

    题意:给定(n)没有区别(K)面骰子,对于(iin [2,2K])求出有多少种骰子序列使得任意两个骰子的点数和不为(i)

    考虑对于一种点数限制(i),如果使用了点数为(j)的骰子,那么点数为(i-j)的骰子就不能使用了

    于是对于一种限制(i),我们可以把(1)(K)的点数(j)分一下类

    • (j eq i-j,i-jin [1,K]),即(j)(i-j)是两种不同的合法点数,则这两种点数只能出现一种

    • (i-j otin [1,K]),即(j)这种点数的出现没有限制

    • (i-j=j),即(i=2j),这个时候点数(j)只能出现一次

    我们发现对于不同的(i),都能分成这三类,且第三类会出现当且仅当(i)是偶数时

    于是我们可以对前两种情况进行讨论

    我们记第一种情况点数对有(cnt1),第二种情况点数有(cnt2)

    假设我们有两个数组,一个(dp_{i,j})表示用不超过(i)对互斥点数对凑出(j)个数有多少情况,(f_{i,j})表示用(i)种点数凑成(j)个数有多少情况,我们的答案就是

    [sum_{j=0}^ndp_{cnt1,j} imes f_{cnt2,n-j} ]

    (i)为偶数的时候,还需要加上(sum_{j=0}^{n-1}dp_{cnt1,j} imes f_{cnt2,n-1-j}),即空出一个数给( frac{i}{2})的请况

    考虑(f,dp)如何求出

    (f)比较好求,显然有(f_{i,j}=sum_{k=0}^jf_{i-1,k}),即对于第(i)种点数枚举一下它选了多少个

    (dp)表示的含义是互斥点数对,于是对于一对互斥点数对,可以是出现两种点数之一,于是(dp_{i,j}=dp_{i-1,j}+2 imessum_{k=0}^{k-1}dp_{i-1,k}),即枚举这一对点对选了多少个,由于两种都可以填,所以要乘(2)

    代码

    #include<bits/stdc++.h>
    #define re register
    #define min(a,b) ((a)<(b)?(a):(b))
    #define max(a,b) ((a)>(b)?(a):(b))
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    const int mod=998244353;
    const int maxn=2005;
    int n,m,a[maxn];
    int dp[maxn][maxn],f[maxn][maxn];
    inline int qm(int x) {return x>=mod?x-mod:x;}
    inline int dqm(int x) {return x<0?x+mod:x;}
    inline int calc(int n,int a,int b) {
    	int now=0;
    	for(re int j=0;j<=n;j++)
    		now=qm(now+1ll*dp[a][j]*f[b][n-j]%mod);
    	return now;
    }
    int main() {
    	scanf("%d%d",&m,&n);
    	a[0]=1;dp[0][0]=1;for(re int i=1;i<=m;i++) dp[i][0]=1;
    	for(re int i=1;i<=m;i++) {
    		for(re int j=1;j<=n;j++)
    			a[j]=qm(a[j-1]+dp[i-1][j]);
    		for(re int j=1;j<=n;j++)
    			dp[i][j]=qm(2ll*a[j-1]%mod+dp[i-1][j]);
    	}
    	for(re int i=0;i<=m;i++) f[i][0]=1;
    	for(re int i=1;i<=m;i++)
    		for(re int j=1;j<=n;j++)
    			f[i][j]=qm(f[i][j-1]+f[i-1][j]);
    	int cnt1=0,cnt2=0,ans=0;
    	for(re int i=2;i<=2*m;++i) {
    		cnt1=cnt2=0;
    		for(re int j=1;j<=m;j++) {
    			if(i-j==j) continue;
    			if(i-j>=1&&i-j<=m) {
    				if(j<i-j) ++cnt1;
    			}
    			else ++cnt2;
    		}
    		ans=calc(n,cnt1,cnt2);
    		if(!(i&1)) ans=qm(ans+calc(n-1,cnt1,cnt2));
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
    
    
  • 相关阅读:
    设计模式-单件模式 实现
    设计模式-观察者模式 实现
    设计模式-策略模式 实现
    笔记- 设计模式:设计原则
    EventBus 发布/订阅 机制的 java 实现
    webService 客户端 以wsimport方式生成对应java文件
    【安装mysql】windows安装压缩版mysql5.7.15
    eclipse插件开发入门
    Java程序开发.邱加永2.1节
    Mysql常用表操作 | 单表查询
  • 原文地址:https://www.cnblogs.com/asuldb/p/11620967.html
Copyright © 2011-2022 走看看