zoukankan      html  css  js  c++  java
  • JZOJ6344. 【NOIP2019模拟2019.9.7】Huge Counting

    Description

    在这里插入图片描述
    T<=10,k<=9;l,r<=1e12

    Solution

    • 显然如果没有mod 2 的话,f(x1…xn),就是从(1…1)走到(x1…xn)方案数
    • 把所有的x全部减一,则
      f(x1,x2...,xn)=(xi)!xi!f(x1,x2...,xn)=frac {(sum xi)! }{prod xi!}
    • 接下来我们只用考虑上式是否有2这个因子,如果没有就是奇数,那么mod 2 就有1的贡献。
    • s!s!中2的因子的个数为s2isum frac {s} {2^i}
    • 所以上式f的2的因子个数就是(除法皆为下取整)
      (xi2kxi2k)sum (frac {sum xi} {2^k}-sum frac {xi}{2^k})
    • 显然对于任意一个k,括号里的都大于等于0。
    • 考虑整除2k就相当于在2进制下把后k位截掉。
    • 如果有两个x在k位上都为1,那么相加之后进位到k+1位,而这里的又被截掉了,所以就会对k+1位的结果有+1的贡献。这样的话就会有大于0个2的因子了。
    • 所以我们可以得出结论,如果要满足有贡献,这些二进制下每一位所有的x中最多只有一个1.
    • 设状态记录哪几位顶住了上限,状压DP一下。
    • 因为有区间,所以容斥一下就好了
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define maxn 10
    #define ll long long 
    #define mo 990804011
    #define Q(i) (1ll<<i)
    using namespace std;
    
    int T,n,i,j,k,opt[1<<maxn];
    ll l[maxn],r[maxn],x[maxn],f[2][1<<maxn-1];
    
    
    ll Doit(){
    	for(i=1;i<=n;i++) if (x[i]<0) return 0;
    	ll mx=0; 
    	for(i=1;i<=n;i++) mx=max(mx,x[i]);
    	int cnt=0; while (mx) mx>>=1,cnt++;
    	memset(f[cnt&1],0,sizeof(f[cnt&1]));
    	
    	f[cnt&1][Q(n)-1]=1;
    	for(k=cnt-1;k>=0;k--) {
    		int p=k&1,q=p^1;
    		memset(f[p],0,sizeof(f[p]));
    		for(int S=0;S<Q(n);S++) if (f[q][S]){
    			int T=0;
    			for(int i=1;i<=n;i++) if ((S&Q(i-1))&&!(x[i]&Q(k)))
    				T+=Q(i-1);
    			f[p][T]+=f[q][S];
    			for(int i=1;i<=n;i++) if ((x[i]&Q(k))||!(S&Q(i-1))){
    				if (S&Q(i-1)) f[p][T^Q(i-1)]+=f[q][S];
    				else f[p][T]+=f[q][S];
    			}
    		}
    		for(int S=0;S<Q(n);S++) if (f[p][S]>=mo)
    			f[p][S]%=mo;
    	}
    	ll sum=0;
    	for(int S=0;S<Q(n);S++) sum+=f[0][S];
    	return sum%mo;
    }
    
    int main(){
    	freopen("c.in","r",stdin);
    	freopen("c.out","w",stdout);
    	scanf("%d",&T);
    	opt[0]=1;
    	for(i=1;i<1<<maxn;i++) opt[i]=-opt[i-(i&-i)];
    	while (T--){
    		scanf("%d",&n);
    		for(i=1;i<=n;i++) scanf("%lld%lld",&l[i],&r[i]);
    		ll ans=0;
    		for(int RS=0;RS<(1<<n);RS++){
    			for(i=1;i<=n;i++) if (RS&Q(i-1)) x[i]=l[i]-2;
    				else x[i]=r[i]-1;
    			(ans+=opt[RS]*Doit()%mo+mo)%=mo;
    		}
    		printf("%lld
    ",ans);
    	}
    } 
    
  • 相关阅读:
    【leetcode】1215.Stepping Numbers
    【leetcode】1214.Two Sum BSTs
    【leetcode】1213.Intersection of Three Sorted Arrays
    【leetcode】1210. Minimum Moves to Reach Target with Rotations
    【leetcode】1209. Remove All Adjacent Duplicates in String II
    【leetcode】1208. Get Equal Substrings Within Budget
    【leetcode】1207. Unique Number of Occurrences
    【leetcode】689. Maximum Sum of 3 Non-Overlapping Subarrays
    【leetcode】LCP 3. Programmable Robot
    【leetcode】LCP 1. Guess Numbers
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/13090969.html
Copyright © 2011-2022 走看看