zoukankan      html  css  js  c++  java
  • 平时十六测

    ---恢复内容开始---

    题解;

    第一题:简单状压 dp[i][s]表示处理到第i位,他的上一位(1),当前位置(2),下一位的状态为s的方案数(4);

    我每次保证i这个s状态合法,然后往下讨论i+1的情况;

    #include<bits/stdc++.h>
    using namespace std;
    const int mod = 1e9 + 7;
    const int M = 1e6 + 5;
    int dp[M][(1<<3)+1];
    inline int go(char a){
        switch(a){
            case '?': return 3;
            case '2': return 2;
            case '1': return 1;
            case '0': return 0;
            case '*': return 4;
        }
    }
    inline int up(int &x, int b){
        x += b;
        if(x >= mod) x -= mod;
    }
    char ss[M];
    int main(){
        freopen("mine.in","r",stdin);
        freopen("mine.out","w",stdout);
        scanf("%s", ss);
        int len = strlen(ss);
        int t = go(ss[0]);
        if(t == 0) dp[0][0] = 1;
        else if(t == 1) dp[0][4] = 1;
        else if(t == 4) dp[0][2] = 1, dp[0][6] = 1;
        else if(t == 3) dp[0][0] = dp[0][2] = dp[0][4] = dp[0][6] = 1;
        for(int i = 0; i < len - 1; i++)
            for(int s = 0; s < (1<<3); s++){
                if(dp[i][s]){
                    int t = go(ss[i+1]);
                    int p1 = s&2 ? 1 : 0, p2 = s&4 ? 1 : 0;
                    if(t == 0){
                        if(!p1 && !p2) up(dp[i+1][s>>1], dp[i][s]);
                    }
                    else if(t == 1){
                        if(p1 && !p2) up(dp[i+1][s>>1], dp[i][s]);
                        if(!p1 && !p2) up(dp[i+1][s>>1|4], dp[i][s]);
                    }
                    else if(t == 2){
                        if(p1 && !p2) up(dp[i+1][s>>1|4], dp[i][s]);
                    }
                    else if(t == 3){
                        up(dp[i+1][s>>1], dp[i][s]);
                        up(dp[i+1][s>>1|4], dp[i][s]);
                    }
                    else if(t == 4){
                        if(p2) {
                            up(dp[i+1][s>>1], dp[i][s]);
                            up(dp[i+1][s>>1|4], dp[i][s]);
                        }
                    }
                    //printf("%d %d %d
    ", i, s, dp[i][s]);
                }
            }
        int ans = 0;
        t = go(ss[len-1]);
        if(t == 0) up(ans, dp[len-1][0]);
        else if(t == 1) up(ans, dp[len-1][1]);
        else if(t == 4) up(ans, dp[len-1][3]), up(ans, dp[len-1][2]);
        else if(t == 3) up(ans, dp[len-1][0]), up(ans, dp[len-1][1]), up(ans, dp[len-1][2]), up(ans, dp[len-1][3]);
        printf("%d
    ", ans);
    }
    View Code

    第二题:

    这道题可以爆搜+剪枝过;对于一个坑,

    1.他流出去变成0;

    2.周围太高,他被累积在里面;

    1可以暴力bfs+记忆化 O(N*N);

    2.比他低的我就流出去覆盖,比他高的就在七中找最小值,还是加一个记忆化;

    以下就是zyy大佬的优美搜索:

    #include<bits/stdc++.h>
    
    inline int read() {
        char c;
        int res = 0, f = 1;
        while((c = getchar()) < '0' || c > '9')    if(c == '-')    f = -f;
        while(c >= '0' && c <= '9') {
            res = res * 10 + c - '0';
            c = getchar();
        }
        return res * f;
    }
    
    const int MAXN = 300 + 5;
    const int INF = 0x7fffffff;
    
    int dx[4] = {0, 0, 1, -1}, dy[4] = {1, -1, 0, 0};
    int n, m;
    int h[MAXN][MAXN], ans[MAXN][MAXN], vis1[MAXN][MAXN], vis2[MAXN][MAXN];
    int dft, tmp;
    
    bool inMap(int x, int y) {
        return x >= 0 && y >= 0 && x <= n + 1 && y <= m + 1;
    }
    
    void dfr(int x, int y) {
        if(vis1[x][y])    return;
        vis1[x][y] = true;
        for(int k = 0; k < 4; k++) {
            int xx = x + dx[k], yy = y + dy[k];
            if(!inMap(xx, yy)) {
                ans[x][y] = 0;
            } else if(h[xx][yy] <= h[x][y]){
                dfr(xx, yy);
                if(ans[xx][yy] == 0)    ans[x][y] = 0;
            }
        }
    }
    
    bool dfs(int x, int y, int u) {
        if(vis2[x][y] == dft)    return true;
        if(h[x][y] > u) {
            tmp = std::min(tmp, h[x][y] + ans[x][y]);
            return true;
        }
        if(ans[x][y] == 0)
            return false;
        vis2[x][y] = dft;
        for(int k = 0; k < 4; k++) {
            int xx = x + dx[k], yy = y + dy[k];
            if(!dfs(xx, yy, u))    return false;
        }
        return true;
    }
    
    struct Point {
        int x, y, height;
    
        bool operator < (const Point &t) const {
            return height > t.height;
        }
    } points[MAXN * MAXN];
    
    int main() {
        freopen("water.in", "r", stdin);
        freopen("water.out", "w", stdout);
    
        n = read(), m = read();
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++) {
                h[i][j] = read();
                points[(i - 1) * m + j] = (Point) {i, j, h[i][j]};
            }
        std::sort(points + 1, points + 1 + n * m);
        memset(ans, -1, sizeof(ans));
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                dfr(i, j);
        for(int i = 1; i <= n * m; i++) {
            dft++;
            tmp = INF;
            if(!dfs(points[i].x, points[i].y, points[i].height))
                ans[points[i].x][points[i].y] = 0;
            else
                ans[points[i].x][points[i].y] = tmp - points[i].height;
        }    
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++)
                printf("%d ", ans[i][j]);
            printf("
    ");
        }
    }
    View Code

    正解:最小生成树;

    对于可以走出去(矩形外)的,这个路径上的最大值是可以确定的,我们考虑在里面的点和外界连通,那么他第一次通向外界的边就是当前最小生成树加上的这条边,而且这条边是通向外界的最小路径上的最大边(思考),所以在里面封闭的一团的答案就是这条边的权值;

    #include<bits/stdc++.h>
    using namespace std;
    
    int zl[4][2] = {{0,1}, {1,0}, {-1,0}, {0,-1}};
    int ans[305][305], mp[305][305], f[305*305], n, m, pd[305*305], h[320*320], cnt;
    struct Edge{int u, v, w;}g[900000];
    struct edge{int v, nxt;}G[900000];
    bool cmp(Edge A, Edge B){return A.w < B.w;}
    void add(int u, int v){
        G[++cnt].v = v, G[cnt].nxt = h[u], h[u] = cnt;
    }
    inline int id(int x, int y){
        return x*(m+2) + y;
    }
    int find(int x){return f[x] == x ? x : f[x] = find(f[x]);}
    void dfs(int x, int w){
        ans[x/(m+2)][x%(m+2)] = w;
        for(int i = h[x]; i; i = G[i].nxt){
            int v = G[i].v;
            dfs(v, w);
        }
    }
    
    int main(){
        freopen("water.in","r",stdin);
        freopen("water.out","w",stdout);
        int tot = 0;
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                scanf("%d", &mp[i][j]);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                for(int k = 0; k < 4; k++){
                    int x = i + zl[k][0], y = j + zl[k][1];
                    g[++tot] = (Edge) {id(i, j), id(x, y), max(mp[i][j], mp[x][y])};
                }
        /*for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++)printf("%d ",id(i,j));puts("");
        }*/
        for(int i = 0; i <= id(n+1, m+1); i++) f[i] = i;
        for(int i = 0; i <= n+1; i++){
            pd[id(i, 0)] = pd[id(i, m+1)] = 1;    
        } 
        for(int i = 0; i <= m+1; i++){
            pd[id(0, i)] = pd[id(n+1, i)] = 1;
        } 
        sort(g + 1, g + 1 + tot, cmp);
        for(int i = 1; i <= tot; i++){
            int fu = find(g[i].u), fv = find(g[i].v);
            if(fu == fv) continue;
            if(pd[fu] && !pd[fv]){
                dfs(fv, g[i].w);
            }
            else if(pd[fv] && !pd[fu]){
                dfs(fu, g[i].w);
            }
            f[fv] = fu;
            pd[fu] |= pd[fv];
            add(fu, fv);
            //printf("%d %d %d %d %d %d
    ", fu/(m+2), fu%(m+2), fv/(m+2), fv%(m+2), pd[fu], pd[fv]);
        }
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++)printf("%d ", ans[i][j] - mp[i][j]);
            puts("");
        }
            
        
    }
    View Code

    第三题:(为什么我觉得这道题考过,而且当时就是yl大佬讲的?我可以失去了记忆)

    求不互质的显然比求互质的更困难,所以我们求互质的;

    互质联想到什么,拆分质因数!

    容斥:我们减去gcd都是2倍数的贡献,减去是3倍数的贡献,加上是6倍数的贡献……

    发现有以下性质:

    1.容斥原理对每个数的质因数拆分,奇减偶加;

    2.如果一个质因数出现了两次,如2*3*5*5,筛2,3,5的时候就会把后面的贡献处理掉,这个多余的5没用,他整个数对后面也没有用;

    所以质因数出现两次,贡献为0;

    3.1的贡献是1;

    这个恰好符合莫比乌斯函数的性质:https://www.cnblogs.com/peng-ym/p/8647856.html

    #include<bits/stdc++.h>
    using namespace std;
    
    #define ll long long
    const int M = 500005;
    bool in[M], vis[M];
    int a[M], mul[M], tot, prime[M], cnt[M];
    void init(){
        mul[1] = 1;
        for(int i = 2; i < M; i++){
            if(!vis[i]) prime[++tot] = i, mul[i] = -1;
            for(int j = 1; j <= tot && i * prime[j] < M; j++){
                int m = i * prime[j];
                vis[m] = 1;
                if(i % prime[j] == 0)break;
                mul[m] = -mul[i];
            }
        }
    }
    ll ans = 0;
    
    void add(int x, int opt){
        for(int i = 1; i * i <= x; i++){
            if(x % i)continue;
            ans -= ( (ll) cnt[i] * (cnt[i] - 1) / 2 * mul[i] ) ;
            cnt[i] += opt;
            ans += ( (ll) cnt[i] * (cnt[i] - 1) / 2 * mul[i] );
            if(x / i == i)continue;
            ans -= ( (ll) cnt[x/i] * (cnt[x/i] - 1) / 2 * mul[x/i] );
            cnt[x/i] += opt;
            ans += ( (ll) cnt[x/i] * (cnt[x/i] - 1) / 2 * mul[x/i] );  
        }
    }
    int read(){
        int x = 0; int f = 1; char c = getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
        return x*=f;
    }
    int main(){
        freopen("gcd.in","r",stdin);
        freopen("gcd.out","w",stdout);
        init();
        int n = read(), m = read();
        for(int i = 1; i <= n; i++) a[i] = read();
        while(m--){
            int u = read();
            if(in[u])add(a[u], -1);
            else add(a[u], 1);
            in[u] ^= 1;
            printf("%lld
    ", ans);
        }
    }
    View Code

    ---恢复内容结束---

  • 相关阅读:
    Linux防火墙配置(iptables, firewalld)
    利用RMAN恢复整个数据库
    RMAN常用命令汇总!
    Oracle RMAN 恢复数据库到不同主机(二)
    Oracle RMAN 恢复数据库到不同主机(一)
    linux sar命令详解
    Linux定时任务Crontab命令详解
    Win7 U盘安装Ubuntu16.04 双系统详细教程
    linux定时任务crontab
    linux服务器端口netstat
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/9858322.html
Copyright © 2011-2022 走看看