zoukankan      html  css  js  c++  java
  • [ARC093F] Dark Horse

    [题目链接]

    https://atcoder.jp/contests/arc093/tasks/arc093_d

    [题解]

    首先一个重要观察是 , (1) 无论在哪个位置其贡献都是一样的 , 因此只需考虑 (1)(1) 号位的答案 , 最后将其乘以 (2 ^ {N}) 就是最终的答案。

    (1) 在一号位时 , 会和 ((2) , (3 , 4) , (5 , 6 , 7 , 8)....) 这些区间的最小值比较。 也就是说 , 这 (N) 个区间的最小值不能是给定的 (M) 个数中的某一个。

    考虑容斥原理 ,用总方案数 - 至少一个区间不满足 + 至少两个区间不满足 + ......

    不妨将 (M) 个数从大到小排序 , 从前往后进行动态规划 , 设 (f_{S , i}) 表示 (N) 个区间的占有情况为 (S) , 考虑到第 (i) 个数的方案数。 那么转移只需考虑是否用当前数 "占有" 一个区间即可 , 需要乘上一个组合数。

    时间复杂度 : (O(2 ^ NN))

    [代码]

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i , l , r) for (int i = (l); i < (r); ++i)
    
    typedef long long LL;
    
    const int MN = 17 , mod = 1e9 + 7 , MS = 1 << 17;
    
    int n , m , a[MN] , fac[MS] , dp[MN][MS] , ifac[MS] , cnt[MS] , all;
    
    inline bool cmp(int x , int y) {
    	  return x > y;
    }
    inline void inc(int &x , int y) {
    	  x = x + y < mod ? x + y : x + y - mod;
    }
    inline void dec(int &x , int y) {
    	  x = x - y >= 0 ? x - y : x - y + mod;
    }
    inline int qPow(int a , int b) {
    	  int c = 1;
    	  for (; b; b >>= 1 , a = 1ll * a * a % mod) if (b & 1) c = 1ll * c * a % mod;
    	  return c;
    }
    inline int binom(int n , int m) {
    	  if (n < m) return 0;
    	  else return 1ll * fac[n] * ifac[m] % mod * ifac[n - m] % mod;
    }
    
    int main() {
    		
    		scanf("%d%d" , &n , &m);
    		for (int i = 1; i <= m; ++i) scanf("%d" , &a[i]);
    		sort(a + 1 , a + 1 + m , cmp);
    		fac[0] = 1; all = 1 << n;
    		for (int i = 1; i <= all; ++i) fac[i] = 1ll * fac[i - 1] * i % mod;
    		ifac[all] = qPow(fac[all] , mod - 2);
    		for (int i = all - 1; i >= 0; --i) ifac[i] = 1ll * ifac[i + 1] * (i + 1) % mod;
    		cnt[0] = 0;
    		for (int i = 1; i < all; ++i) cnt[i] = cnt[i >> 1] + (i & 1);
    		dp[0][0] = 1;
    		for (int i = 1; i <= m; ++i)
    			  for (int s = 0; s < all; ++s) if (dp[i - 1][s]) {
    			  		inc(dp[i][s] , dp[i - 1][s]);
    			  		for (int j = 0; j < n; ++j)
    			  				if ((s >> j & 1) == 0) inc(dp[i][s | 1 << j] , 1ll * dp[i - 1][s] * binom(all - s - a[i] , (1 << j) - 1) % mod * fac[1 << j] % mod);  				
    				}
    		int ans = 0;
    		for (int s = 0; s < all; ++s)
    				if (cnt[s] & 1) dec(ans , 1ll * dp[m][s] * fac[all - s - 1] % mod);
    				else inc(ans , 1ll * dp[m][s] * fac[all - s - 1] % mod);
    		printf("%d
    " , 1ll * ans * all % mod);
    	  return 0; 
    }
  • 相关阅读:
    根据IP头格式 写sniff
    双零碎安设Linux之后找不到Windows分区
    Oracle的共享封锁 独有封锁和共享更新封锁 (3)
    设置配备部署Windows与Linux平台的DATA GURAD (1)
    GTick 桌面节拍器
    在文本终端怎样查看上一屏内容(终端回滚快捷键)
    肃清Cache影响手动逼迫革新Buffer Cache
    Oracle数据库无法加载_OraMTS_的处理赏罚设置装备安置
    Linux操纵琐细下确立DBCA报错的料理要领
    设置Windows与Linux平台的DATA GURAD (2)
  • 原文地址:https://www.cnblogs.com/evenbao/p/14321147.html
Copyright © 2011-2022 走看看