6月训练
https://ac.nowcoder.com/acm/contest/17148/L
sqrt没判负数,WA4发
SRM589 FlippingBitsDiv1
题意:给定长N的01串S,每次操作翻转一个字符或翻转前$kM$个字符,求最少多少次操作使得长$n-m$的前缀等于后缀
画一下可以发现,最后$S$一定以$M$为循环节
如果$M\le 17$,直接$2^M$枚举最终串,再O(N)DP求出最小值
如果$M > 17$,那么块数$cnt \le 17$,$2^{cnt}$枚举每个前缀块翻转情况,再O(N)统计最小值
#include <bits/stdc++.h> using namespace std; class FlippingBitsDiv1 { public: int n, m, cnt, dp[333][2]; char s[333], t[333]; int dif(int x, int u) { int ans = 0, now = 0; for (int i=(x-1)*m; i<n&&i<x*m; ++i) ans += (s[i]^u)!=t[now++]; return ans; } int solve() { for (int i=0; i<n; ++i) s[i] -= '0'; cnt = n/m; int ans = n; if (m<=cnt) { for (int k=0; k<(1<<m); ++k) { for (int j=0; j<m; ++j) t[j] = k>>j&1; dp[cnt][1] = 1+dif(cnt,1)+dif(cnt+1,0); dp[cnt][0] = dif(cnt,0)+dif(cnt+1,0); for (int i=cnt-1; i; --i) { dp[i][0] = min(dp[i+1][0]+dif(i,0),dp[i+1][1]+dif(i,0)+1); dp[i][1] = min(dp[i+1][1]+dif(i,1),dp[i+1][0]+dif(i,1)+1); } ans = min(ans, dp[1][0]); ans = min(ans, dp[1][1]); } } else { for (int k=0; k<(1<<cnt); ++k) { int ret = 0; for (int x=0; x<m; ++x) { int p[2]{}, tot = 0; for (int u=x,d=0; u<n; u+=m,++d) ++p[s[u]^k>>d&1], ++tot; ret += min(tot-p[0], tot-p[1]); } int ok = 0; for (int x=cnt-1; x>=0; --x) { if (k>>x&1) ok = 1; if (ok&&(k>>x&1)!=(k>>x+1&1)) ++ret; } ans = min(ans, ret); } } return ans; } int getmin(vector<string> S, int M) { string tmp; for (auto &t:S) tmp += t; n = tmp.size(); m = M; for (int i=0; i<n; ++i) s[i] = tmp[i]; return solve(); } };
http://106.75.49.226/problem/ADPC1-Z-K
矩阵快速幂系数不为定值,可以分别考虑每一种矩阵
https://codeforces.com/contest/1526/problem/E
题目等价于找一个最大值最小的序列a,使得后缀数组为s
比赛的时候想的是,先初始化a为全1,如果后缀不比上一个大,就把当前位++,但这样与上个后缀暴力比较的话要O(N^2),或者写个动态Hash要$O(N\log^2)$,最后也没搞出来
实际上比较两个后缀$i$和$j$,由于后缀$i+1$和后缀$j+1$大小是确定的,只用考虑$a_{i}$和$a_{j}$的大小就行了
https://codeforces.com/contest/1523/problem/D
不少于$\frac{n}{2}$个元素满足性质,考虑随机化就行了
ccpc2017哈尔滨写过这个套路了,结果比赛的时候竟然没想出来
https://codeforces.com/gym/103117/problem/B
模拟题,细节写错好几发
https://codeforces.com/contest/1537/
打了把div2,感觉变菜好多
BC想复杂,写时间太久,D题筛因子竟然写错
E1很简单,猜个结论,十分钟过了,后面就剩40分钟,画E2也没画出,有个结论是A^INF < B^INF等价于A+B<B+A,之前看过没想起来
F题挺简单,可惜比赛没时间看这个。每次操作不改变奇偶性,和为奇直接判NO。再画一下发现如果是二分图,合法等价于两部的和相等,如果有奇环的话一定合法。
https://codeforces.com/contest/1523/problem/E
题意:$n$盏灯,初始全灭,每次随机选一盏灭的灯点亮,直到存在连续$k$盏灯有$2$盏是亮的就结束,求结束时的期望点灯数
求期望考虑转化成方案数来做,可以发现不合法情况的方案数很好求,因为一个不合法的情况是与点灯次序是无关的
设$g_{i,j}$为前$i$盏灯中,点了$j$盏,不考虑点灯次序时,不合法条件的方案数,就可以得到$g_{i,j}=g_{i,j}+g_{i-k,j-1},j>1$, 初始值$g_{i,1}=i$
考虑答案怎么用$g$来表示,假设恰好$x$次操作结束方案数为$w_x$,那么对答案贡献为$\frac{xw_x}{n\cdot (n-1) \cdots (n-x+1)}$
考虑求$w_x$,也就是总方案减去不合法方案再减去$x$次操作之前就合法的方案,就可以得到$w_x=\binom{n}{x}x!-g_{n,x}x!-\sum\limits_{y=1}^{x-1} w_y \binom{n-y}{x-y}(x-y)!$
上面的和式很容易前缀优化到$O(1)$,那么只需要求出$g_{n,x} (2\le x \le n)$即可,直接求$g$的复杂度是$O(n^2)$的,考虑优化
分别考虑每个初始点$(1,1),(2,1),...,(n,1)$对$g_{n,x}$的贡献,画下图可以得到
$g_{n,x}=\sum\limits_{i=1}^n \binom{n-i-kx+k+x-1}{n-i-kx+k}=\binom{n-1-kx+k+x}{x}-\binom{-1-kx+k+x}{x}$
这样单组数据总复杂度就为$O(n)$
#include <bits/stdc++.h> using namespace std; const int N = 1e5+10, P = 1e9+7; int fac[N], ifac[N], dp[N], f[N]; int qpow(int a, int n) { int ans = 1; for (; n; n>>=1,a=a*(int64_t)a%P) if (n&1) ans=ans*(int64_t)a%P; return ans; } int C(int64_t n, int m) { if (m>n||m<0) return 0; return fac[n]*(int64_t)ifac[m]%P*ifac[n-m]%P; } int main() { fac[0] = 1; for (int i=1; i<N; ++i) fac[i] = fac[i-1]*(int64_t)i%P; ifac[N-1] = qpow(fac[N-1], P-2); for (int i=N-2; i>=0; --i) ifac[i] = ifac[i+1]*(i+1ll)%P; int T; cin >> T; while (T--) { int n, k; cin >> n >> k; int ans = 0; for (int x=2; x<=n; ++x) { int64_t L = -1-k*(int64_t)x+k+x, R = L+n; int g = C(R,x)-C(L,x); dp[x] = (fac[n]*(int64_t)ifac[n-x]-g*(int64_t)fac[x]-f[x-1]*(int64_t)ifac[n-x])%P; f[x] = (f[x-1]+dp[x]*(int64_t)fac[n-x])%P; ans = (ans+x*(int64_t)dp[x]%P*ifac[n]%P*fac[n-x])%P; } if (ans<0) ans += P; printf("%d\n", ans); } }