zoukankan      html  css  js  c++  java
  • [BZOJ4903/CTSC2017]吉夫特

    Description
    简单的题目,既是礼物,也是毒药。
    B 君设计了一道简单的题目,准备作为 (gift) 送给大家。
    输入一个长度为 (n) 的数列(a_1,a_2,…,a_n)
    问有多少个长度大于等于 2 的不上升的子序列 (a_{b_1},a_{b_2},…,a_{b_k}) 满足

    [prod_{i = 2}^k inom{a_{b_{i-1}}}{a_{b_i}} \% 2= inom{a_{b_1}}{a_{b_2}} imes inom{a_{b_2}}{a_{b_3}} imes cdots imes inom{a_{b_{k-1}}}{a_{b_k}} \% 2 > 0$$输出这个个数对 1000000007 取模的结果。 G 君看到题目后,为大家解释了一些基本概念。 我们选择任意多个整数 $b_i$ 满足$$1leqslant b_1<b_2<⋯<b_k−1<b_kleqslant n$$我们称 $a_{b_1},a_{b_2},…,a_{b_k}$ 是 a 的一个子序列。 如果这个子序列同时还满足$$a_{b_1}geqslant a_{b_2}geqslant ⋯geqslant a_{b_{k−1}}geqslant a_{b_k}$$我们称这个子序列是不上升的。 组合数 $inom{n}{m}$ 是从 $n$ 个互不相同的元素中取 $m$ 个元素的方案数,具体计算方法如下:$$inom{n}{m} = frac{n!}{m!(n-m)!} = frac{n imes (n - 1) imes cdots imes 2 imes 1}{(m imes (m - 1) imes cdots imes 2 imes 1)((n-m) imes (n-m - 1) imes cdots imes 2 imes 1)}]

    这里要特别注意,因为我们只考虑不上升子序列,所以在求组合数的过程中,一定满足 (ngeqslant m),也就是 (inom{a_{b_i}−1}{a_{b_i}}) 中一定有 (a_{b_i}−1geqslant a_{b_i})
    我们在这里强调取模 (x\%y) 的定义:

    [x \% y = x - left lfloor frac{x}{y} ight floor imes y ]

    其中 (lfloor n floor) 表示小于等于 (n) 的最大整数。
    (x\%2>0),就是在说 (x) 是奇数。
    与此同时,经验告诉我们一个长度为 (n) 的序列,子序列个数有 (O(2n)) 个,所以我们通过对答案取模来避免输出过大。
    B 君觉得 G 君说的十分有道理,于是再次强调了这些基本概念。
    最后,G 君听说这个题是作为 (gift) 送给大家,她有一句忠告。
    "Vorsicht, Gift!"
    “小心……剧毒!”

    Input
    第一行一个整数 (n)
    接下来 (n) 行,每行一个整数,这 (n) 行中的第 (i) 行,表示(a_i)

    Output
    一行一个整数表示答案。

    Sample Input
    4
    15
    7
    3
    1

    Sample Output
    11

    HINT

    • 对于前 10% 的测试点,(nleqslant 9,1leqslant a_ileqslant 13)
    • 对于前 20% 的测试点,(nleqslant 17,1leqslant a_ileqslant 20)
    • 对于前 40% 的测试点,(nleqslant 1911,1leqslant aileqslant 4000)
    • 对于前 70% 的测试点,(nleqslant 2017)
    • 对于前 85% 的测试点,(nleqslant 100084)
    • 对于 100% 的测试点, (1leqslant nleqslant 211985,1leqslant a_ileqslant 233333)。所有的(a_i)互不相同,也就是说不存在(i,j)同时满足(1leqslant i<jleqslant n)(a_i=a_j)

    题目说了(\%2),那不就是要=1就好了。然后组合数(inom{m}{n}\%2),嗯,Lucas定理啊。。。然后这不就只剩4种情况了?(inom{0}{0}=1,inom{1}{0}=1,inom{0}{1}=1,inom{1}{1}=1),就一个等于0,肯定就它不能出现对吧?那就是不能存在(a_{b_i})为偶,(a_{b_{i+1}})为奇的情况。但其实,这个性质没啥作用。。。
    我们换个方向考虑,从Lucas定理的角度考虑,我们知道Lucas定理是:(inom{m}{n}\%2=inom{lfloorfrac{m}{2} floor}{lfloorfrac{n}{2} floor}\%2 imesinom{m\%2}{n\%2}),然后这个是不是很熟悉?二进制分解!如果说存在某一位(m)为1,(n)不为1,那么,答案就为0了。所以,答案不为0的情况,当且仅当(n&m=m),答案为1。所以我们可以直接枚举一个集合的超集转移过来,或者枚举一个集合的子集,转移过去。

    /*program from Wolfycz*/
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')    f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x>=10)	print(x/10);
    	putchar(x%10+'0');
    }
    const int N=211985,M=233333,p=1e9+7;
    int f[M+10],val[N+10];
    bool vis[M+10];
    int main(){
    	int n=read(),Ans=0;
    	for (int i=1;i<=n;i++)	f[val[i]=read()]=1;
    	for (int i=1;i<=n;i++){
    		int sta=val[i];
    		for (int s=(sta-1)&sta;s;s=(s-1)&sta){
    			if (vis[s])	continue;
    			f[s]=(f[s]+f[sta])%p;
    		}
    		vis[sta]=1;
    	}
    	for (int i=1;i<=n;i++)	Ans=(Ans+f[val[i]])%p;
    	printf("%d
    ",(Ans-n+p)%p);
    	return 0;
    }
    
  • 相关阅读:
    Kendo UI
    Docker
    jQuery DataTables && Django serializer
    MySQL ODBC for Linux
    mongoengine
    Python之多线程
    Python中的正则表达式
    通过恢复目录(Catalogue)进行PDB级别的PITR恢复
    执行PDB的PITR恢复失败的说明
    在PDB级别中如何切换或重建UNDO表空间
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/9683421.html
Copyright © 2011-2022 走看看