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();
}
};
View Code

 

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);
    }
}
View Code

 

posted @ 2021-06-15 23:06  dz8gk0j  阅读(71)  评论(0编辑  收藏  举报