codeforces 840 C. On the Bench(多重集合的交错排列经典题目)

来源:互联网 发布:画板软件在线 编辑:程序博客网 时间:2024/05/22 08:13

题目链接

C. On the Bench

分析

这是一道多重集合交错排列的经典题目,经典的题意是这样的:

设集合 An1a1,n2a2,...,niai 问使其相邻两个数不相同的排列有多少种.

我们先来解决这个经典题目,然后再来解决codeforces的这个题目.
可以用 dp+容斥做
先来解决一个简化的问题
dp[k] 表示将这些数分成 k 块 每块的数的是一样的,并且每块数量至少为1,那么我们可以通过递推来求这个dp数组

dp[i][k] 表示考虑前 i个数分成 k 块的个数,那么,

dp[i][k]=j=1kdp[i1][kj](ni1j1)ni!j!

上面那个不就是个背包吗?递推就好了

知道了dp[k] 之后,就可以用容斥了,

dp[k]k! 表示的是有 nk个数相邻

所以有

ans=dp[n]n!dp[n1](n1)!++(1)(ni)dp[i]i!

将原题的完全平方数处理掉就是经典问题了

AC code

#include<bits/stdc++.h>#define pb push_back#define mp make_pair#define PI acos(-1)#define fi first#define se second#define INF 0x3f3f3f3f#define INF64 0x3f3f3f3f3f3f3f3f#define random(a,b) ((a)+rand()%((b)-(a)+1))#define ms(x,v) memset((x),(v),sizeof(x))#define scint(x) scanf("%d",&x );#define scf(x) scanf("%lf",&x );#define eps 1e-10#define dcmp(x) (fabs(x) < eps? 0:((x) <0?-1:1))#define lc o<<1#define rc o<<1|1using namespace std;typedef long long LL;typedef long double DB;typedef pair<int,int> Pair;const int maxn = 300+10;const int MAX_V= 500+10;const int MOD = 1e9+7;LL a[maxn];LL C[maxn][maxn];LL A[maxn];LL dp[maxn][maxn];std::map<LL, int> ma;LL power_mod(LL x,LL n){   LL ret =1;   while (n) {      if(n&1)ret = ret * x %MOD;      x = x*x %MOD;      n >>=1;   }   return ret;}void init(){   C[0][0] = 1;   for(int i=1 ; i<maxn ; ++i){      C[i][0] =1;      for(int j=1 ; j<maxn ; ++j){         C[i][j] =(C[i-1][j] + C[i-1][j-1]) % MOD;      }   }   A[0]=1;   for (int i=1 ; i<maxn ; ++i) A[i] = A[i-1]*i % MOD;}int main(){    ios_base::sync_with_stdio(0);    cin.tie(0);    cout.tie(0);    int n;    init();    cin>>n;    for(int i=0 ; i<n ; ++i){      LL x;cin>>x;      for(int j=2 ; j*j <= x ; ++j){         while (x % (j*j) ==0) {            x/=(j*j);         }      }      ma[x] ++;   }   ms(dp,0);dp[0][0] =1;   int cnt =1;   for(auto e : ma){      for(int i=1 ; i<=n ; ++i){         //dp[cnt-1][0] =1;         int m = min(e.se,i);         for(int j = 1 ; j<=m ; ++j){            LL tmp = A[e.se];            tmp  = tmp * C[e.se-1][j-1] % MOD;            tmp = tmp *power_mod(A[j],MOD-2) % MOD;            dp[cnt][i] += dp[cnt-1][i-j]*tmp;            dp[cnt][i] %= MOD;         }      }      cnt ++;   }   //for(int i=0 ; i<=n ; ++i)std::cout << dp[cnt-1][i] << '\n';   LL ans =dp[cnt-1][n] *A[n]% MOD;int k=0;   for(int i =n-1 ; i>=0 ; --i){      if(k&1)ans = (ans+dp[cnt-1][i]*A[i] )% MOD;      else{         ans = (ans - dp[cnt -1][i] * A[i] + MOD) % MOD;      }      k ^=1;   }   std::cout << ans << '\n';    //std::cout << "time "<< clock()/1000 <<"ms"<< '\n';    return 0;}
原创粉丝点击