来自学长的馈赠5
B. mine
看到题面一头雾水,看到文字版题解一头雾水,看到代码……感觉很显然确实没啥好写的……
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e6 + 10; const int N = 1e6 + 2; const ll mod = 1e9 + 7; char s[maxn]; int n; ll f[maxn][4]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { scanf("%s", s+1); n = strlen(s+1); if(s[1] == '?') { f[1][0] = 1, f[1][1] = 1, f[1][2] = 1; } else { if(s[1] == '*') f[1][2] = 1; else f[1][s[1]-'0'] = 1; } for(int i=2; i<=n; i++) { if(s[i] == '?') { f[i][2] = (f[i-1][1]+f[i-1][2])%mod; f[i][0] = (f[i-1][0]+f[i-1][2])%mod; f[i][1] = (f[i-1][0]+f[i-1][2])%mod; } else { if(s[i] == '*') f[i][2] = (f[i-1][1]+f[i-1][2])%mod; if(s[i] == '0') f[i][0] = f[i-1][0]; if(s[i] == '1') f[i][0] = f[i-1][2], f[i][1] = f[i-1][0]; if(s[i] == '2') f[i][1] = f[i-1][2]; } } printf("%lld\n", (f[n][0]+f[n][2])%mod); return 0; }
C. 小凯的疑惑
直接记结论好了gcd(a, b)=1的时候不能用ax+by表示出来的正整数(x和y也是正整数)一共有(a-1)*(b-1)/2个.
我查了半天各种题解并研究了半天,但是终于还是没看懂那些或长篇大论或过分简洁的证明,我表示放弃了。我还是用打表大法来找结论吧。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1507; int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); } inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { int x = read(), y = read(); if(gcd(x, y)!=1) { printf("-1\n"); exit(0); } printf("%lld", 1ll*(x-1)*(y-1)/2); return 0; }
D. 排序
二分答案,找到一个尽量大的标准(>=某数)把当前查找的位置上的数包括进去,中间排序的操作用线段树维护,op=0把区间内前小于标准的cnt个数全设为0,其余的全设为1,op=1把区间内大于标准的cnt个数全设为1,其余的全设为0.
二分的模板有两个来自进阶指南,一个是找满足条件的里尽量大的,另一个是找满足条件的里尽量小的,我本来以为要找大于等于的第一个,所以要用求尽量小的答案的模板,但是它不对,然后我忽然发现我枚举的是比大于等于当前数的标准,然后只要当前数在大于等于的范围内是符合条件,所以标准越小越容易满足条件,但是要找恰好的位置,所以这个大于等于的标准应该恰好卡死,也就是说其实要找最大的答案。
不过用像Chen_jr大佬一样的二分模板就不会出现上述问题。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//Cat 对 %%%Chen_jr%%% 的题解情有独钟 #include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e5 + 2; const ll mod = 1e9 + 7; int n, m, p, a[maxn], now[maxn]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } struct cat { int op, l, r; }o[maxn]; struct tree { struct node { int sum, lazy; }t[maxn<<2]; void pushup(int x) { t[x].sum = t[x<<1].sum + t[x<<1|1].sum; } void build(int x, int l, int r) { t[x].sum = t[x].lazy = 0; if(l == r) { t[x].sum = now[l]; return; } int mid = (l + r) >> 1; build(x<<1, l, mid); build(x<<1|1, mid+1, r); pushup(x); } void pushdown(int x, int l, int r) { int ls = x<<1, rs = x<<1|1, mid = (l + r) >> 1; if(t[x].lazy == 1) { t[ls].sum = mid - l + 1; t[rs].sum = r - mid;//居然写成了r-l t[ls].lazy = t[rs].lazy = 1; } else { t[ls].sum = t[rs].sum = 0; t[ls].lazy = t[rs].lazy = -1; } t[x].lazy = 0; } void update(int x, int l, int r, int L, int R, int upd) { if(L > R) return; if(L <= l && r <= R) { if(upd) { t[x].sum = r - l + 1; t[x].lazy = 1; } else { t[x].sum = 0; t[x].lazy = -1; } return; } if(t[x].lazy) pushdown(x, l, r); int mid = (l + r) >> 1; if(L <= mid) update(x<<1, l, mid, L, R, upd); if(R > mid) update(x<<1|1, mid+1, r, L, R, upd); pushup(x); } int query(int x, int l, int r, int L, int R) { if(L <= l && r <= R) { return t[x].sum; } if(t[x].lazy) pushdown(x, l, r); int mid = (l + r) >> 1, ans = 0; if(L <= mid) ans += query(x<<1, l, mid, L, R); if(R > mid) ans += query(x<<1|1, mid+1, r, L, R); return ans; } }T; bool check(int mid) { for(int i=1; i<=n; i++) now[i] = a[i] >= mid ? 1 : 0; T.build(1, 1, n); for(int i=1; i<=m; i++) { int cnt = T.query(1, 1, n, o[i].l, o[i].r); int u1 = 1, u0 = 0; if(o[i].op) swap(u1, u0); else cnt = o[i].r - o[i].l + 1 - cnt; T.update(1, 1, n, o[i].l, o[i].l+cnt-1, u0); T.update(1, 1, n, o[i].l+cnt, o[i].r, u1); } return T.query(1, 1, n, p, p); } int main() { n = read(); m = read(); for(int i=1; i<=n; i++) a[i] = read(); for(int i=1; i<=m; i++) { o[i].op = read(), o[i].l = read(), o[i].r = read(); } p = read(); int l = maxn, r = -maxn; for(int i=1; i<=n; i++) { l = min(l, a[i]); r = max(r, a[i]); } while(l < r) { //printf("l = %d r = %d\n", l, r); int mid = (l + r + 1) >> 1; if(check(mid)) l = mid; else r = mid - 1; } printf("%d\n", l); return 0; }
时光花火,水月星辰