zoukankan      html  css  js  c++  java
  • 6月训练

    https://ac.nowcoder.com/acm/contest/17148/L

    sqrt没判负数,WA4发

    SRM589 FlippingBitsDiv1

    题意:给定长N的01串S,每次操作翻转一个字符或翻转前$kM$个字符,求最少多少次操作使得长$n-m$的前缀等于后缀

    画一下可以发现,最后$S$一定以$M$为循环节

    如果$Mle 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(Nlog^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}{ncdot (n-1) cdots (n-x+1)}$

    考虑求$w_x$,也就是总方案减去不合法方案再减去$x$次操作之前就合法的方案,就可以得到$w_x=inom{n}{x}x!-g_{n,x}x!-sumlimits_{y=1}^{x-1} w_y inom{n-y}{x-y}(x-y)!$

    上面的和式很容易前缀优化到$O(1)$,那么只需要求出$g_{n,x} (2le x le n)$即可,直接求$g$的复杂度是$O(n^2)$的,考虑优化

    分别考虑每个初始点$(1,1),(2,1),...,(n,1)$对$g_{n,x}$的贡献,画下图可以得到

    $g_{n,x}=sumlimits_{i=1}^n inom{n-i-kx+k+x-1}{n-i-kx+k}=inom{n-1-kx+k+x}{x}-inom{-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
    ", ans);
        }
    }
    View Code
  • 相关阅读:
    (dfs)codeforces 767C
    配置vscode c/c++像sublime那样按Ctrl+shift+B编译直接运行
    (JAVA)使用swing组件模仿QQ界面+网络编程实现QQ消息传输
    (dp)hihocoder
    (暴力+精度)hihocoder
    区域赛43天
    区域赛第33天
    区域赛41天
    最小和最大表示法
    HDU 6166 二进制划分集合
  • 原文地址:https://www.cnblogs.com/fs-es/p/14887603.html
Copyright © 2011-2022 走看看