关于此题转移方程正确性的求助
查看原帖
关于此题转移方程正确性的求助
314535
abcdeffa楼主2021/11/25 15:56

这题当时我脑子抽风了写了个 O(n4m2)O(n^4m^2) 的 DP,设法是设 fi,j,S,pf_{i, j, S, p} 表示当前选定了 ii 个数(钦定 {a}\{a\} 单调不降),当前最大的 a=2j1a = 2^{j - 1}j=0j = 0 时表示没有数),SS 是进位状态,即二进制下第 jj 位往后的状态,pp 是已经确定的 1 的个数。每次转移就是找一个状态 fi,j,S,pf_{i, j, S, p},给到一个新状态 fii,jj,SS,ppf_{ii, jj, SS, pp}

由于我当时不知道怎么想的枚举了 jjjj(同时钦定 ii>iii > i),因此复杂度多了一个 mm,但我认为这个转移的正确性是没有问题的,但它在你站数据上 WA 了 4 个点(11~13、16),另一 OJ 上 WA 的点也一模一样。

今天将枚举 jjjj 去掉,令其为 (j+1)(j + 1),且不要求 ii>iii > i,这样就直接 A 了。

我不能理解这是为什么,请问能否说明其错误之处或给组小数据?感激不尽!

#include <cstdio>
#define mod 998244353
#define maxN 35
#define maxM 105
long long val[maxM];
long long Pow[maxM][maxM];
long long Fac[maxM], Inv[maxM];
long long f[maxN][maxM][(1 << 5)][maxN];
long long Max (long long x, long long y)
{
	return x > y ? x : y;
}
long long Lowbit (long long x)
{
	return x & (-x);
}
long long Count (long long x)
{
	long long cnt = 0;
	while(x)
	{
		cnt++; x -= Lowbit(x);
	}
	return cnt;
}
long long C (long long N, long long M)
{
	if(M > N)
	{
		return 1;
	}
	return Fac[N] * Inv[M] % mod * Inv[N - M] % mod;
}
long long getPow (long long x, long long y)
{
	if(!y)
	{
		return 1;
	}
	else
	{
		long long res = getPow(x, y >> 1);
		if(!(y & 1))
		{
			return res * res % mod;
		}
		else
		{
			return res * res % mod * x % mod;
		}
	}
}
int main ()
{
//	freopen("sequence.in", "r", stdin);
//	freopen("sequence.out", "w", stdout);
	Fac[0] = 1;
	for(long long i = 1;i < maxN; i++)
	{
		Fac[i] = Fac[i - 1] * i % mod;
	}
	Inv[maxN - 1] = getPow(Fac[maxN - 1], mod - 2);
	for(long long i = maxN - 2;i >= 0; i--)
	{
		Inv[i] = Inv[i + 1] * (i + 1) % mod;
	}
	long long n = 0, m = 0, K = 0; scanf("%lld %lld %lld", &n, &m, &K);
	for(long long i = 0;i <= m; i++) scanf("%lld", &val[i]);
	for(long long i = 0;i <= m; i++)
	{
		Pow[i][0] = 1;
		for(long long j = 1;j <= n; j++)
		{
			Pow[i][j] = Pow[i][j - 1] * val[i] % mod;
		}
	}
	f[0][0][0][0] = 1;
	for(long long i = 0;i < n; i++)
	{
		for(long long j = 0;j <= (m + 1); j++)
		{
			for(long long S = 0;S < (1 << 5); S++)
			{
				for(long long p = 0;p <= K; p++)
				{
					if(!f[i][j][S][p]) continue;
					for(long long ii = i;ii <= n; ii++)
					{
						long long jj = j + 1;
						long long preS = ii - i;
						long long SS = ((S >> (jj - j - 1)) + preS);
						long long Lost = S - ((S >> (jj - j - 1)) << (jj - j - 1));
						long long pp = p + Count(Lost) + (SS & 1);
						SS = (SS >> 1);
						if(pp <= K)
						{
							f[ii][jj][SS][pp] = (f[ii][jj][SS][pp] + f[i][j][S][p] * C(n - i, ii - i) % mod * Max(Pow[jj - 1][ii - i], 1) % mod) % mod;
						}
					}
				}
			}
		}
	}
	long long Ans = 0;
	for(long long j = 0;j <= (m + 1); j++)
	{
		for(long long S = 0;S < (1 << 5); S++)
		{
			for(long long p = 0;p <= K; p++)
			{
				if(p + Count(S) <= K)
				{
					Ans = (Ans + f[n][j][S][p]) % mod;
				}
			}
		}
	}
	printf("%lld", Ans);
	return 0;
}

考场代码不同的转移部分:

for(long long jj = j + 1;jj <= (m + 1); jj++)
2021/11/25 15:56
加载中...