nomura2020_f Sorting Game

nomura2020_f Sorting Game

https://atcoder.jp/contests/nomura2020/tasks/nomura2020_f\

UPmbqK.png

Tutorial

https://img.atcoder.jp/nomura2020/editorial.pdf

https://atcoder.jp/contests/nomura2020/submissions/14860490

考虑当Snuke操作完之后,序列合法的条件就是,不存在无法交换的逆序对,也就是,不存在\(x<y\)满足\(a_x>a_y\)\(a_x,a_y\)的二进制位相差超过一个位置.称此为条件1

考虑对于Snuke而言,有效的操作序列只有\(i,i+1,\cdots,N\).因为对于\(x<y\),若对\(j<i-1\)操作,假如\((j+1,i)\)区间内\(a_x,a_y\)二进制相等,那么等价于\(j,j+1,\cdots,N\),否则\(a_x,a_y\)的大小关系不变,不同的二进制位置减少,对Takahashi来说是更优的.那么在Snuke操作前合法的\(a\)序列满足对于每种有效操作序列满足条件1,称其为条件2

观察所有数第\(i\)位,假如第\(i\)位之前都满足条件2,分为两种情况.

  1. 没有1在0之前,此时条件2依然满足.

  2. 存在1在0之前,观察最左边的1和最右边的0对应的数,首先它们的前\(i-1\)位应该相等,考虑在它们之间的数,若其第\(i\)位是0,那么它的前\(i-1\)位也应和最左边的1相同,若其第\(i\)位为1,那么如果它前\(i-1\)位与最左边的1不同,那么最右边的0的前\(i\)位也就与它不同;综上它们之间的所有数前\(i-1\)位相同.

用DP统计,设\(dp(i,j)\)表示\(n=i,m=j\)时的答案,第一种情况就枚举0,1分界点的位置,第二种情况就枚举一个长度为\(k<j\)的序列,选择其中的一个数复制\(j-k\)次,这\(j-k+1\)个数满足第\(i\)位,它们中最左边的数为1,它们的左边的数为0,它们中最右边的数为0,它们右边的数为1,其他的\(j-k-1\)个数任意.

\[dp(i,j)=dp(i-1,j)(j+1)+\sum_{k<j} dp(i-1,k)k \cdot 2^{j-k-1} \]

Code

#include <cstdio>
#include <iostream>
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
inline char gc() {
//	return getchar();
	static char buf[100000],*l=buf,*r=buf;
	return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
}
template<class T> void rd(T &x) {
	x=0; int f=1,ch=gc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
	while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=gc();}
	x*=f;
}
typedef long long ll;
const int mod=1e9+7;
const int maxn=5000+5,maxm=5000+5;
int n,m;
int pow2[maxm],inv2[maxm];
int dp[maxn][maxm],sum[maxn][maxm];
int main() {
	rd(n),rd(m);
	pow2[0]=1,pow2[1]=2;
	inv2[0]=1,inv2[1]=(mod+1)>>1;
	for(int i=2;i<=m;++i) {
		pow2[i]=(ll)pow2[i-1]*pow2[1]%mod;
		inv2[i]=(ll)inv2[i-1]*inv2[1]%mod;
	}
	for(int i=1;i<=m;++i) {
		dp[1][i]=pow2[i];
		sum[1][i]=(sum[1][i-1]+(ll)dp[1][i]*i%mod*inv2[i])%mod;
	}
	for(int i=2;i<=n;++i) for(int j=1;j<=m;++j) {
		dp[i][j]=((ll)dp[i-1][j]*(j+1)+(ll)sum[i-1][j-1]*pow2[j-1])%mod;
		sum[i][j]=(sum[i][j-1]+(ll)dp[i][j]*j%mod*inv2[j])%mod;
	}
	printf("%d\n",dp[n][m]);
	return 0;
}
posted @ 2020-07-06 15:55  LJZ_C  阅读(324)  评论(0编辑  收藏  举报