1 条题解
-
2Takagi-san (njnu19200437) LV 10 MOD @ 2022-02-06 10:48:24
提示1: +lowbit 和 +highbit 两种运算的作用相互抵消。
考虑变化中 \(x\) 的二进制,思考为什么成立。
提示2:在\([2^i, 2^{i+1})\)的数中,设操作区间中 +lowbit 的次数比 +highbit 的次数多 \(t\) 次(*),对于 \(t=0,1,...\) 有多少个数可以变为 \(2^a\) 的形式?可以写暴力程序打表找规律,也可以数学推导。
这里建议打表,很快可以发现规律。
提示3:本题的优化。
①想知道操作序列中取一个长度不超过 \(k\) 的连续子列,\(1\) 的个数与 \(0\) 的个数的差值的最大值。可以采用前缀和+单调队列(滑动窗口) 优化。
②打表的结果应该类似于杨辉三角
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
...
杨辉三角每一列的前缀和有通项公式,所以答案可以按每一列计算,再加起来。总的时间复杂度 \(O(d)\) ,(不采取这两个优化,时间复杂度是\(O(k(n+d))\))
Code:
#include <bits/stdc++.h> using namespace std; using ll = long long; const ll mod = 1e9+7; ll powmod(ll a, ll b){ ll res = 1;a %= mod; assert(b >= 0); for (; b; b >>= 1) { if (b & 1) res = res * a % mod; a = a * a % mod; } return res; } ll inv(ll x) { return powmod(x, mod - 2); } ll cal(ll t, ll x) { ll q = x, now = x, res = x; for(int i=1;i<=t;i++) { now = now * (--q) % mod * inv(i+1) % mod; res = (res + now) % mod; } return res; } class Mqueue{ struct node{ int index; int val; }; int k, now = 0, min = false; // true: 最大值 deque<node> q; public: Mqueue(int a, bool b = false): k(a), min(b){} void push(int x) { now++; while(!q.empty()&&q.front().index+k<=now) q.pop_front(); if(!min) while(!q.empty()&&q.back().val<=x) q.pop_back(); else while(!q.empty()&&q.back().val>=x) q.pop_back(); q.push_back((node){now,x}); } int getval(){return q.front().val;} }; int main() { ll m, n, k, d; cin>>m>>n>>k>>d; string s; cin>>s; int a[d+1] = {0}; for(int i=1;i<=d;i++) a[i] = (s[i-1] == '1' ? -1 : 1); for(int i=2;i<=d;i++) a[i] += a[i-1]; Mqueue Q(k, true); int l = 0; for(int i=1;i<=d;i++) { l = max(l, a[i] - Q.getval()); Q.push(a[i]); } cout <<(1 + cal(l, n) - cal(l, m) + mod) % mod; return 0; }
(*)严格来说,这里应该表述为,操作区间[l,r]的所有前缀[l,x]中,+lowbit的次数比+highbit的次数至多多 \(t\) 次。
- 1
信息
- ID
- 1321
- 难度
- 9
- 分类
- (无)
- 标签
- (无)
- 递交数
- 23
- 已通过
- 1
- 通过率
- 4%
- 被复制
- 1
- 上传者