题意:
思路:
考虑如何构造连边使得
B
o
b
o
Bobo
Bobo当前选择的点是最优的选择,需要一直以维护这个最优为目的来构造。
考虑当前点如果被涂色且序号为 i i i的话,那么表示这个点至少要连出去一条边,为了避免重复计数答案,我们只考虑比 i i i大的 j j j点,即点权值 2 j > 2 i 2^j > 2^i 2j>2i,很明显所有的点权值比当前大的点我都可以和它连边,但是不可以不连,(因为不连边的话,而又要保证当前点是被染色的点,那么就一定要向小的点权节点连边,但是如果这样的话,完全可以不染色 i i i点,就可以达到目的,所以很明这是与之前矛盾的),还有一种特殊情况就是,假如和当前的点 i i i相连的所有 j j j点如果都是被染色的也不行,因为这种连边情况下,我完全没有必要再添加 i i i的点权来达到目的,因为前面的已经够了,与最小的和又矛盾了。
考虑当前的点未被染色的情况,那么很明显如果要连边的话,他一定是和被染色的点连边,否则和未染色的点连,不合法…,而且也可以选择不连。
所以我们从点权值由大到小,维护一下走过了几个点(点权比它大),走过的点中有多少被染色了,组合数统计答案就可以了。
#include <bits/stdc++.h>
using namespace std;
#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 1e5 + 10;
const int MOD = 1e9 + 7;
char s[N];
ll n;
int col[N];
ll ksm(ll a,ll b) {
ll res = 1;
while(b) {
if(b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res % MOD;
}
// 考虑 怎么维护连边 使得给出的这个x染色点是最优的选择
// 当一条边的两个端点中的任意一个被染色后 这条边就被染色了
int main() {
while(~scanf("%lld",&n)) {
scanf("%s",s);
int len = strlen(s);
ll tot = n - len;//点权值比我大的点
ll ans = 1,done = 0;
for(ll i = 0;i < len;i ++) {
if(s[i] == '1') {
ll tmp = ksm(2LL,tot);
tmp = (tmp - ksm(2LL,done) + MOD) % MOD;
ans = ans * tmp % MOD;
done++;
}
else ans = ans * ksm(2LL,done) % MOD;
tot++;
}
printf("%lld\n",ans);
}
return 0;
}