2019牛客国庆集训派对day2 J.Vertex Cover(思维,组合数学算贡献)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019牛客国庆集训派对day2 J.Vertex Cover(思维,组合数学算贡献)相关的知识,希望对你有一定的参考价值。
从序号最大的点开始考虑
考虑 ( i , j ) (i,j) (i,j)(其中 i < j i<j i<j)这条边,选和不选的方案数放在 i i i点考虑
这样可以做到不重不漏
设 p p p表示权值大于 i i i且被选择的点数, q q q表示权值大于 i i i且没被选择的点数
①.若点 i i i被选择(只考虑 ( i , j ) (i,j) (i,j)边,其中 i < j i<j i<j)
那么至少存在一个代价更大且没被选择的点和 i i i相连
如果不是这样,完全可以不选 i i i而把其他小于 i i i的点全选上,更优
如果是这样,那么可以保证 i i i会被选择
方案数是 ( 2 q − 1 ) ∗ 2 p (2^{q}-1)*2^p (2q−1)∗2p
②.若点 i i i没有被选择(只考虑 ( i , j ) (i,j) (i,j)边,其中 i < j i<j i<j)
显然 i i i不可能和其他代价更大且没有被选择的点相连
显然 i i i可能和所有代价更大且被选择的点相连
这样最优,方案数是 2 q 2^q 2q
累乘即是答案
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 1e6+10;
const int mod = 1e9+7;
int base[maxn],n;
char a[maxn];
signed main()
{
base[0] = 1;
for(int i=1;i<=1000000;i++) base[i] = base[i-1]*2%mod;
while( cin >> n >> ( a+1 ) )
{
int p = 0 , q = 0 , ans = 1;//被选择的点,没有被选择的点
reverse( a+1,a+1+strlen(a+1) );
for(int i=strlen(a+1)+1;i<=n;i++) a[i] = '0';
for(int i=n;i>=1;i--)
{
if( a[i]=='0' )//不被选择
ans = ans*base[p]%mod,q++;
else
ans = ans*( base[q]-1 )%mod*base[p]%mod,p++;
}
cout << (ans%mod+mod)%mod << endl;
}
}
以上是关于2019牛客国庆集训派对day2 J.Vertex Cover(思维,组合数学算贡献)的主要内容,如果未能解决你的问题,请参考以下文章
2019牛客国庆集训派对day2 C Just h-index 二分答案+主席树