大家好,时隔一年,我复活了!
这两题并没有什么关系,只是一起A掉了就顺便一起写个题解吧……
CF 285D
打表
看了好久没有什么想法,猜测答案不会太大就直接打表。
发现n为偶数答案就是0。
n为13可以秒出,n为15大概等一会儿就好了,恩然后就过了。
打表代码不小心删了,反正不难写吧。
CF 285E
计数DP
第一反应记f[i][j][k][0/1][0/1]表示1~i已经填进去,且此时恰有j个位置满足good position,k表示下标大于i+1的位置有多少数,后面两个0/1表示i+1和i+2位置有没有数。因为下标大于i+1的数对i没有影响,所以每一个位置有数字的概率都是相等的,这样乘上一个分数就能知道i+2有数字的方案数。转移就是枚举i+1放哪里,这样且不论是不是对的,已经是三方的了。
发现有个k很难受,考虑优化掉它。之所以要记k,是因为不满足good position的数放在后面是有后效性的。要免去k,就干脆不放这些数,最后乘上阶乘表示随便放。那么这样就不能保证恰好j个位置满足,然而我们发现这样就能使用容斥了。观察发现对于状态中的j个good,一个实际上有m个good的方案会被算C(m,l)。那就直接容斥吧。
#include<cstdio>
#define N 1005
#define MOD 1000000007
using namespace std;
int f[N][N][2][2], F[N];
int C[N][N], fac[N];int main()
{int n, k;scanf("%d%d",&n,&k);C[0][0] = 1;for(int i = 1; i <= n; i++){C[i][0] = 1;for(int j = 1; j <= i; j++)C[i][j] = (C[i-1][j] + C[i-1][j-1]) % MOD;}fac[0] = 1; for(int i = 1; i <= n; i++) fac[i] = 1ll * fac[i-1] * i % MOD;f[1][0][0][0] = 1;f[1][1][0][1] = 1;for(int i = 1; i < n; i++)for(int j = 0; j <= i; j++){for(int s1 = 0; s1 <= 1; s1++) for(int s2 = 0; s2 <= 1; s2++){if(!s1) (f[i+1][j+1][s2][0] += f[i][j][s1][s2])%=MOD; // put i+1 on iif(i != n-1) (f[i+1][j+1][s2][1] += f[i][j][s1][s2])%=MOD; // put i+1 on i+2(f[i+1][j][s2][0] += f[i][j][s1][s2])%=MOD;}}for(int j = 0; j <= n; j++){F[j] = f[n][j][0][0] + f[n][j][1][0];F[j] = 1ll * F[j] * fac[n-j] % MOD;}for(int i = n; i >= 0; i--)for(int j = n; j > i; j--)(F[i] -= 1ll * F[j] * C[j][i] % MOD) %= MOD;printf("%d\n",(F[k]+MOD)%MOD);}