题解 [JXOI2012]奇怪的道路
Posted Administrator-9
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 [JXOI2012]奇怪的道路相关的知识,希望对你有一定的参考价值。
考场上我坚持认为这是个组合数题。。。
看到\\(k\\leq8\\)我想状压来着,但是不知道怎么压
实际上,对于点i和点j的连边(\\(j\\in[i-k, i-1]\\))只有连或不连两种状态
而如果i与比j编号小的点连边的情况已经考虑完了,方案数就可以连带下来,如此就可以建立转移
令\\(dp[i][j][s][l]\\)为在点i,连了j条边,点i-k到点i之间的点已连边数的奇偶性压成s,此时从前向后连带到第\\(i-k+l\\)个点
i与每个点都是连或不连两种状态,则正序枚举l,使\\(dp[i][j][s][max(0, k-i)]\\)为初始状态
则连带过程:
\\(dp[i][j][s][l+1] += dp[i][j][s][l]\\) (i与j不连边)
\\(dp[i][j+1][s^(1<<(k-l))^1][l] += dp[i][j][s][l]\\) (i与j连边)
注意这里\\(l\\in[0, k-1]\\),但为了方便写成了\\(l\\in[0, k]\\),
当\\(i==k\\)时考虑从第i个点转移到第i+1个点,但只有第i-k个点连边为偶数时可以转移。
\\(dp[i+1][j][s<<1][max(0, k-i)] += dp[i][j][s][k]\\)
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 32
#define ll long long
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long
int n, m, k;
ll dp[N][N][1<<9][9];
const ll p=1e9+7;
inline void mod(ll& a, ll b) {a+=b; if (a>=p) a-=p;}
signed main()
{
#ifdef DEBUG
freopen("1.in", "r", stdin);
#endif
scanf("%d%d%d", &n, &m, &k);
int lim = 1<<(k+1);
dp[1][0][0][k] = 1;
for (int i=1,cnt,s2; i<=n; ++i)
for (int j=0; j<=m; ++j)
for (int s=0; s<lim; ++s)
for (int l=0; l<=k; ++l) {
if (i-k+l <= 0) continue;
cnt=0; s2=s;
while (s2) {++cnt; s2&=(s2-1);}
//if (cnt>j*2) continue;
//if (dp[i][j][s][l]) cout<<i<<\' \'<<j<<\' \'<<s<<\' \'<<l<<\' \'<<cnt<<endl;
if (l==k) {
if (!(s&(1<<k))) mod(dp[i+1][j][s<<1][max(0, k-i)], dp[i][j][s][k]);
}
else {
//if (dp[i][j][s][l]) cout<<i<<\' \'<<j<<\' \'<<s<<\' \'<<l<<\' \'<<cnt<<endl;
mod(dp[i][j+1][s^(1<<(k-l))^1][l], dp[i][j][s][l]);
mod(dp[i][j][s][l+1], dp[i][j][s][l]);
//if (dp[i][j][s][l]) {
//cout<<dp[i][j+1][s^(1<<(k-l))^1][l+1]<<endl;
//cout<<bitset<10>(s^(1<<(k-l))^1)<<endl;
//}
}
//if (i==2) printf("dp[%d][%d][%d][%d]=%lld\\n", i, j, s, l, dp[i][j][s][l]);
}
printf("%lld\\n", dp[n][m][0][k]);
return 0;
}
以上是关于题解 [JXOI2012]奇怪的道路的主要内容,如果未能解决你的问题,请参考以下文章