A:建设城市(city)
答案就是至少有0个不满足条件的方案数
减去至少1个的
加上至少2个的
以此类推
就可以直接做了
考虑0个的怎么求
m个队 分成n组 方案数就是C(m-1,n-1);
不会的建议找数学老师谢罪
有i个不满足条件的方案数可以用挡板法
假定此时有i个不满足条件
那就挑出ik个 令其固定 不参与剩下的分配
然后在其他的分配好之后 将这ik个给到i个城市
那么这个城市一定不满足
所以有i个不满足条件的方案数就求出来了
B:军训队列
同一个身高的人是等效的
所以去重之后直接dp就可以了
dp[i][j] 表示前i个人 分成j组 最小的答案
(n^2*k)转移就可以了
C:山屋惊魂
大模拟
D:彩球问题
发现并不关心具体是哪个球
如果当前的球状态是 1 3 2 3
而它和1 2 3 3 是等价的
故我们只关心cnt为1 cnt为2 cnt为3的球有多少个
因此就可以记搜了
dp[i][j][k][l] 表示 当前有1个的球有多少种 有2个的球有多少种 有3个的球有多少种 上次放的是哪种球
然后就可以简单转移了
#include<bits/stdc++.h>
using namespace std;
const int maxn = 14;
const int mod = 1e8;
struct ll {
long long x[5];
ll(){memset(x,0,sizeof(x));}
friend void operator += (ll &A,ll B) {
for(int i = 0;i < 5;++i) A.x[i] += B.x[i];
for(int i = 0;i < 5;++i) A.x[i+1] += A.x[i] / mod,A.x[i] %= mod;
}
friend ll operator * (ll A,int B) {
for(int i = 0;i < 5;++i) A.x[i] *= B;
for(int i = 0;i < 5;++i) A.x[i+1] += A.x[i] / mod,A.x[i] %= mod;
return A;
}
friend bool operator != (ll &A,int B) {
return A.x[0] != B;
}
void print(int i = 4){
for(;~i;--i) if(x[i]) {printf("%lld",x[i]);break;}
for(--i;~i;--i) printf("%08lld",x[i]);
}
};
ll dp[maxn][maxn][maxn][5];
int a[maxn];
int cnt[maxn];
ll dfs(int cnt1,int cnt2,int cnt3,int pre){
if(dp[cnt1][cnt2][cnt3][pre] != 0) return dp[cnt1][cnt2][cnt3][pre];
if(!cnt1 && !cnt2 && !cnt3) {
dp[cnt1][cnt2][cnt3][pre].x[0] = 1LL;
return dp[cnt1][cnt2][cnt3][pre];
}
ll ans;
if(cnt1) ans += (dfs(cnt1-1,cnt2,cnt3,0) * (cnt1-(pre==1)));
if(cnt2) ans += dfs(cnt1+1,cnt2-1,cnt3,1) * (cnt2-(pre==2));
if(cnt3) ans += dfs(cnt1,cnt2+1,cnt3-1,2) * (cnt3-(pre==3));
return dp[cnt1][cnt2][cnt3][pre] = ans;
}
int main(){
freopen("color.in","r",stdin);
freopen("color.out","w",stdout);
int n;scanf("%d",&n);
for(int i = 1;i <= n;++i) scanf("%d",&a[i]),cnt[a[i]]++;
dfs(cnt[1],cnt[2],cnt[3],0).print();
return 0;
}