程序设计实习实验班2017推荐习题
区间众数问题
这题写莫队是最容易的,可以对于每种出现次数的数字维护一个堆,用于删除时维护答案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
#include<map> #include<set> #include<cmath> #include<stack> #include<queue> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define inf 0x7fffffff #define ll long long #define pa pair<int,int> using namespace std; ll read() { ll 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*10+ch-'0';ch=getchar();} return x*f; } int n,blo=200; int nl,nr; int v[50005],bl[50005],st[50005],ans[50005],cnt[50005]; struct query{ int l,r,id; }q[50005]; struct data{ int cnt,v; }ANS; bool operator<(data a, data b) { if(a.cnt != b.cnt)return a.cnt < b.cnt; else return a.v > b.v; } priority_queue<data,vector<data> >heap[50005]; bool operator<(query a,query b) { if(bl[a.l]!=bl[b.l])return bl[a.l]<bl[b.l]; if(bl[a.l]&1)return a.r<b.r; else return a.r>b.r; } void add(int x) { cnt[v[x]]++; ANS.cnt=cnt[ANS.v]; int tmp=cnt[v[x]]; auto d=(data){tmp,v[x]}; heap[tmp].push(d); if(ANS<d)ANS=d; } void del(int x) { cnt[v[x]]--; ANS.cnt=cnt[ANS.v]; heap[cnt[v[x]]].push((data){cnt[v[x]],v[x]}); for(int k=0;k<2;k++) { int tmp=cnt[v[x]]+k; while(heap[tmp].size()) { auto top=heap[tmp].top(); if(top.cnt!=cnt[top.v])heap[tmp].pop(); else { if(ANS<top)ANS=top; break; } } } } void query(int l,int r) { while(nr<r) { nr++; add(nr); } while(nl>l) { nl--; add(nl); } while(nr>r) { del(nr); nr--; } while(nl<l) { del(nl); nl++; } } int main() { n=read(); nl=1;nr=0; for(int i=1;i<=n;i++) v[i]=st[i]=read(); sort(st+1,st+n+1); for(int i=1;i<=n;i++) v[i]=lower_bound(st+1,st+n+1,v[i])-st; for(int i=1;i<=n;i++) bl[i]=(i-1)/blo+1; for(int i=1;i<=n;i++) q[i].l=read(),q[i].r=read(),q[i].id=i; sort(q+1,q+n+1); for(int i=1;i<=n;i++) { query(q[i].l,q[i].r); ans[q[i].id]=st[ANS.v]; } for(int i=1;i<=n;i++) printf("%d\n",ans[i]); return 0; } |
「BZOJ3659」Which Dreamed It 神奇钥匙
求以1为起点的欧拉回路的个数乘1的度数
BEST theorem
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
#include<map> #include<set> #include<cmath> #include<stack> #include<queue> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define inf 1000000000 #define ll long long #define pa pair<int,int> #define mod 1000003 using namespace std; ll read() { ll 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*10+ch-'0';ch=getchar();} return x*f; } int n; int a[105][105]; int deg[105]; ll fac[mod + 1]; int gauss(int n) { if(n < 0)return 0; ll det = 1; int flag = 1; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) a[i][j] = (a[i][j] % mod + mod) % mod; for(int i = 1; i <= n; i++) { for(int j = i + 1; j <= n; j++) while(a[j][i]) { ll tmp = a[i][i] / a[j][i]; for(int k = i; k <= n; k++) a[i][k] = ((a[i][k] - a[j][k] * tmp) % mod + mod) % mod; swap(a[i], a[j]); flag = -flag; } if(!a[i][i])return 0; det = det * a[i][i] % mod; } if(flag == -1)return mod - det; return det; } int main() { fac[0] = 1; for(int i = 1; i <= mod; i++) fac[i] = fac[i - 1] * i % mod; while(1) { memset(a, 0, sizeof(a)); memset(deg, 0, sizeof(deg)); n = read(); if(!n)break; for(int i = 1; i <= n; i++) { deg[i] = read(); for(int j = 1; j <= deg[i]; j++) { int x = read(); a[i][x]++; } } for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) if(i == j)a[i][j] = deg[i] - a[i][j]; else a[i][j] = -a[i][j]; if(n == 1 && !deg[1])puts("1"); else { ll ans = 1; for(int i = 1; i <= n; i++) ans = ans * fac[deg[i] - 1] % mod; ans = ans * gauss(n - 1) % mod; ans = ans * deg[1] % mod; cout << ans << endl; } } return 0; } |
「bzoj4031」[HEOI2015]小Z的房间
矩阵树定理
推荐阅读 算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
#include<map> #include<set> #include<cmath> #include<stack> #include<queue> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define inf 1000000000 #define ll long long #define pa pair<int,int> #define mod 1000000000 using namespace std; ll read() { ll 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*10+ch-'0';ch=getchar();} return x*f; } ll a[105][105]; int n, m, id[15][15]; char ch[15][15]; int xx[4] = {1, -1, 0, 0}, yy[4] = {0, 0, 1, -1}; int gauss(int n) { if(n < 0)return 0; ll det = 1; int flag = 1; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) a[i][j] = (a[i][j] % mod + mod) % mod; for(int i = 1; i <= n; i++) { for(int j = i + 1; j <= n; j++) while(a[j][i]) { ll tmp = a[i][i] / a[j][i]; for(int k = i; k <= n; k++) a[i][k] = ((a[i][k] - a[j][k] * tmp) % mod + mod) % mod; swap(a[i], a[j]); flag = -flag; } if(!a[i][i])return 0; det = det * a[i][i] % mod; } if(flag == -1)return mod - det; return det; } int main() { while(1) { memset(a, 0, sizeof(a)); n = read(); m = read(); if(n == 0)break; for(int i = 1; i <= n; i++) scanf("%s", ch[i] + 1); int tmp = 0; for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) if(ch[i][j] != '*') id[i][j] = ++tmp; for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) if(ch[i][j] != '*') for(int k = 0; k < 4; k++) { int x = i + xx[k], y = j + yy[k]; int u = id[i][j], v = id[x][y]; if(x > 0 && y > 0 && x <= n && y <= m && ch[x][y] != '*') a[u][v]--, a[u][u]++; } cout << gauss(tmp - 1) << endl; } return 0; } |
POJ2373 Dividing the Path
用 dp(i) 表示覆盖到 i 的最小喷水装置数,单调队列优化 dp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
#include<map> #include<set> #include<cmath> #include<stack> #include<deque> #include<queue> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define inf 1000000000 #define ll long long #define pa pair<int,int> #define mod 1000003 using namespace std; ll read() { ll 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*10+ch-'0';ch=getchar();} return x*f; } int n, l; int A, B; int dp[1000005]; bool mark[1000005]; struct data{ int x, y; friend bool operator<(data a, data b){ if(a.x == b.x)return a.y < b.y; return a.x < b.x; } }a[1005]; deque<int>q; int main() { n = read(); l = read(); A = read(); B = read(); for(int i = 1; i <= n; i++) a[i].x = read() + 1, a[i].y = read() - 1; sort(a + 1, a + n + 1); int now = 0; for(int i = 1; i <= n; i++) { now = max(now, a[i].x); while(now <= a[i].y) { mark[now] = 1; now++; } } dp[0] = 0; for(int i = 1; i <= l; i++) { if(i >= 2 * A) { while(q.size() && dp[q.back()] > dp[i - 2 * A]) q.pop_back(); q.push_back(i - 2 * A); } while(q.size() && i - q.front() > 2 * B)q.pop_front(); if(mark[i] || (i & 1))dp[i] = inf; else { if(q.size()) { int x = q.front(); dp[i] = dp[x] + 1; } else dp[i] = inf; } } if(dp[l] >= inf)puts("-1"); else cout << dp[l] << endl; return 0; } |
Squares
预处理每个点向右和向下延伸的线段长度,枚举每个正方形左上角的点和边长
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
#include<map> #include<set> #include<cmath> #include<stack> #include<deque> #include<queue> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define inf 1000000000 #define ll long long #define pa pair<int,int> #define mod 1000003 using namespace std; ll read() { ll 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*10+ch-'0';ch=getchar();} return x*f; } int n, m; int D[1505][1505], R[1505][1505]; int main() { while(scanf("%d%d", &n, &m) != EOF) { memset(D, 0, sizeof(D)); memset(R, 0, sizeof(R)); char opt[2]; while(m--) { scanf("%s", opt); int x = read(), y = read(), k = read(); if(opt[0] == 'H') { R[x][y] = k; } else D[x][y] = k; } for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) { D[i][j] = max(D[i][j], D[i - 1][j] - 1); R[i][j] = max(R[i][j], R[i][j - 1] - 1); } int ans = 0; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) for(int k = 1; k <= min(D[i][j], R[i][j]); k++) if(R[i + k][j] >= k && D[i][j + k] >= k) ans++; cout << ans << endl; } return 0; } |
CF449D Jzzhu and Numbers
膜zmx(洵老师233):
直接做不好做,考虑容斥,求出f[s]表示选出若干个数字and起来之后对应于s二进制表示中为1的那些位置必须是1的方案。
考虑and的FWT的过程。
当前只考虑选出1个数字的话,令g[s]表示给定的数中s出现次数。
tf (g ) = (tf (g 0 + g 1), tf (g 1))
事实上就是处理了最高位的情况!这样继续分治下去做就可以弄出只选出1个数字时的f[s]。
考虑取若干个的情况,那么f[s]对应的可选集合{x1, x2, · · · , xf [s]}中的数任选,最后and出来都能保证对应于s的那些位置仍然为1。
令ans[s] = 2^f[s],这里的ans[s]即为选若干个数使得它们and起来对应s的位置必须是1的方案数。
考虑FWT的“意义”。
g[s]表示了and起来恰好是s的方案数,那么做了一次FWT之后求得
了and起来至少是s的方案数tf (g)。 那么IFWT的意义就和FWT相反。
ans[s]表示and起来至少是s的方案数,那么做了一次IFWT之后求得 了and起来恰好是s的方案数utf (ans)。
所求答案就是utf (ans)[0]。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
#include<map> #include<set> #include<cmath> #include<stack> #include<deque> #include<queue> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define inf 1000000000 #define mod 1000000007 #define ll long long #define pa pair<int,int> using namespace std; ll read() { ll 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*10+ch-'0';ch=getchar();} return x*f; } int T; int n, m, L; ll A[1048576]; ll qpow(ll a, ll b) { ll ans = 1; for(ll i = b; i; i >>= 1, a = a * a % mod) if(i & 1)ans = ans * a % mod; return ans; } void fwtand(ll *A, int n) { if(n == 1)return; int h = n >> 1; fwtand(A, h); fwtand(A + h, h); for(int i = 0; i < h; i++) { ll u = A[i], v = A[i + h]; A[i] = (u + v) % mod; A[i + h] = v % mod; } } void ifwtand(ll *A, int n) { if(n == 1)return; int h = n >> 1; for(int i = 0; i < h; i++) { ll u = A[i], v = A[i + h]; A[i] = (u - v) % mod; A[i + h] = v % mod % mod; } ifwtand(A, h); ifwtand(A + h, h); } int main() { T = read(); while(T--) { memset(A, 0, sizeof(A)); n = read(); for(int i = 1; i <= n; i++) { int x = read(); A[x]++; } for(L = 1; L <= 1000000; L <<= 1); fwtand(A, L); for(int i = 0; i < L; i++)A[i] = qpow(2, A[i]); ifwtand(A, L); cout << A[0] << endl; } return 0; } |
SRM518 NIM
FWT xor 卷积
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
#include<map> #include<set> #include<cmath> #include<stack> #include<deque> #include<queue> #include<cstdio> #include<vector> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define inf 1000000000 #define mod 1000000007 #define ll long long #define pa pair<int,int> using namespace std; ll read() { ll 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*10+ch-'0';ch=getchar();} return x*f; } int T; int n, m, L; ll ine; bool mark[50005]; ll A[65536]; ll qpow(ll a, ll b) { ll ans = 1; for(ll i = b; i; i >>= 1, a = a * a % mod) if(i & 1)ans = ans * a % mod; return ans; } void fwt(ll *A, int n) { if(n == 1)return; int h = n >> 1; fwt(A, h); fwt(A + h, h); for(int i = 0; i < h; i++) { ll u = A[i], v = A[i + h]; A[i] = (u + v) % mod; A[i + h] = (u - v + mod) % mod; } } void ifwt(ll *A, int n) { if(n == 1)return; int h = n >> 1; for(int i = 0; i < h; i++) { ll u = A[i], v = A[i + h]; A[i] = (u + v) * ine % mod; A[i + h] = ((u - v + mod) % mod) * ine % mod; } ifwt(A, h); ifwt(A + h, h); } int main() { mark[1] = 1; for(int i = 2; i <= 50000; i++) if(!mark[i]) for(int j = i + i; j <= 50000; j += i) mark[j] = 1; T = read(); ine = qpow(2, mod - 2); while(T--) { memset(A, 0, sizeof(A)); n = read(); m = read(); for(L = 1; L <= m; L <<= 1); for(int i = 1; i <= m; i++) if(!mark[i])A[i] = 1; fwt(A, L); for(int i = 0; i < L; i++)A[i] = qpow(A[i], n); ifwt(A, L); cout << A[0] << endl; } return 0; } |
黄学长怎么区间众数强行多个log啊 不太行吧