zoukankan      html  css  js  c++  java
  • 7月22集训个人赛第三场

    A题,简单图论题: Codeforces 295B floyd变种

    题意:对于一个带权有向图,每次删除一个点,要求计算输出删除该点前当前图的所有点间的最短路径之和。

    解法:对于删除顺序,我们可以反过来做,这样就相当于每次添加一个点到图中,然后询问当前图的所有点间的最短路径之和。对于每次添加操作,就相当于用当前添加的点v,去更新整个图的最短路,也就是dist[s][t] = min(dist[s][t], dist[s][v]+dist[v][t]);

    对于统计操作,直接暴力枚举即可。整个复杂度为O(n^3),唯一需要注意的就是,本题数据范围,需要用long long 来处理。

    #include <stdio.h>
    #include <string.h>
    #define maxn 505
    typedef long long LL;
    
    bool mark[maxn];
    LL dist[maxn][maxn];
    LL seq[maxn];
    LL ans[maxn];
    
    LL min(LL x, LL y){
        return x < y ? x : y;
    }
    
    void update(int s, int n){
        for(int v = 1; v <= n; v ++){
            for(int u = 1; u <= n; u ++){
                dist[v][u] = min(dist[v][u], dist[v][s] + dist[s][u]);
            }
        }
    }
    LL query(int s, int n){
        LL ret = 0;
        for(int i = n, v = seq[i]; i >= s; v = seq[--i]){
            for(int j = n, u = seq[j]; j >= s; u = seq[--j]){
                ret += dist[v][u];
            }
        }
        return ret;
    }
    int main(){
        for(int n; scanf("%d", &n)!=EOF; ){
            for(int i = 1; i <= n; i ++){
                for(int j = 1; j <= n; j ++)
                    scanf("%I64d", &dist[i][j]);
                mark[i] = false;
            }
            for(int i = 1;i <= n; i ++)
                scanf("%d", &seq[i]);
            for(int i = n; i >= 1; i --){
                mark[seq[i]] = 1;
                update(seq[i], n);
                ans[i] = query(i, n);
            }
            for(int i = 1; i <= n; i ++){
                printf("%I64d ", ans[i]);
            }
            printf("\n");
        }
        return 0;
    }
    

    B题,简单数学题: Codeforces 154B

    题意:有n个人,m个操作。每个人有一个编号i,每个人有两种行为,行为+ i,表示编号为i的人需要去做实验,此时需要满足当前正在工作的人(设编号为j)有gcd(i, j) = 1;行为- i表示编号为i的人退出实验。对于每个操作需要判断是否成功。

    解法:操作中最麻烦的就是怎么样查找谁与谁冲突。考虑i,j如果冲突,也就是说gcd(i, j)!=1,那么我们可以对gcd(i, j)分解为若干个素数的乘积,设为pi,显然存在且只存在一个j,使得pi可以整除gcd(i, j)。(否则设存在k与i冲突且pi整除gcd(k, i),那么k肯定与j冲突。) 

    处理:首先预处理出10^5内的素数,然后维护一个数组用于表示对应素数的倍数,初始化为0。然后对于+操作,进行素数分解,然后对于每个素数进行查询倍数,如果不是0,就出现了冲突。对于- 操作,同样进行素数分解,并将对应的素数的倍数赋值为0.对于已操作过,这个可以直接利用一个数组进行标记。整个复杂度为O(nlogn  + nsqrt(n)).

    #include <stdio.h>
    #include <string.h>
    
    #define maxn 100000
    bool f[maxn+5];
    int pos[maxn];
    int p[maxn/10], g[maxn/10];
    int total;
    void process(int n){
        memset(f, 0, sizeof(f));
        total = 0;
        for(int i = 2; i <= n; i ++){
            if(!f[i]){
                pos[i] = total;
                p[total ++] = i;
                for(int j = i; j <= n; j += i){
                    f[j] = 1;
                }
            }
        }
        memset(f, 0, sizeof(f));
        memset(g, 0, sizeof(g));
    }
    int solve(int n){
        for(int i = 2; i*i <= n; i ++){
            if(n%i==0){
                if(g[pos[i]]) return g[pos[i]];
                while(n%i==0) n/=i;
            }
        }
        if(n!=1 && g[pos[n]]) return g[pos[n]];
        return 0;
    }
    int refresh(int n, int x){
        for(int i = 2; i*i<=n; i ++){
            if(n%i==0){
                g[pos[i]] = x;
                while(n%i==0) n/=i;
            }
        }
        if(n!=1) g[pos[n]] = x;
        return 0;
    }
    int main(){
        int n, m, x;
        char cmd[3];
        scanf("%d%d", &n, &m);
        process(n);
        for(int i = 0; i < m; i ++){
            scanf("%s%d", cmd, &x);
            if(cmd[0]=='+'){
                if(f[x]){
                    printf("Already on\n");
                    continue;
                }
                int t = solve(x);
                if(t) printf("Conflict with %d\n", t);
                else {
                    f[x] = 1;
                    refresh(x, x);
                    printf("Success\n");
                }
            }
            else{
                if(!f[x]) printf("Already off\n");
                else f[x] = 0, refresh(x, 0), printf("Success\n");
            }
        }
        return 0;
    }
    

    C题,简单数学题 Codefoces 150B

    题意:对于一个大小为M的字符集,求长度为n的字符串的个数,要求字符串满足对于所有长度为k的连续子串为回文串。

    解法:由于要求长度为k的字符串必须为回文串。那么我们可以先预处理一下哪些位置必须放同样的字符(建图操作)。这样我们就可以将整个位置分成x个集合(直接染色),同一个集合内的位置能放的字符必定是一样的。对于每个集合能放的字符的种类是一样的,所以就是m^x.整个算法的复杂度为O((n-k)*k/2 + n + log m)

     

     1 #include <stdio.h>
     2 #include <string.h>
     3 #define maxn 2005
     4 typedef long long LL;
     5 const LL mod = 1000000007;
     6 
     7 int g[maxn][maxn];
     8 int col[maxn], cnt;
     9 
    10 LL quick_power(LL a, LL b){
    11     LL r = 1;
    12     for(;b;b>>=1){
    13         if(b&1) r = a * r %mod;
    14         a = a * a %mod;
    15     }
    16     return r;
    17 }
    18 void dfs(int v, int f, int c, int n){
    19     col[v] = c;
    20     for(int i = 1; i <= n; i ++){
    21         if(!g[v][i]|| i == f || col[i]) continue;
    22         dfs(i, v, c, n);
    23     }
    24 }
    25 int main(){
    26     int n, m, k;
    27     scanf("%d%d%d", &n, &m, &k);
    28     if(k > n){
    29         printf("%I64d\n", quick_power(m, n));
    30         return 0;
    31     }
    32     for(int i = 1; i + k - 1<= n; i ++){
    33         for(int a = i, b = i + k - 1; a < b; a ++ , b --){
    34             g[a][b] = g[b][a] = 1;
    35         }
    36     }
    37     for(int i = 1; i <= n; i ++){
    38         if(!col[i]){
    39             cnt ++;
    40             dfs(i, -1, cnt, n);
    41         }
    42     }
    43     printf("%I64d\n", quick_power(m, cnt));
    44     return 0;
    45 }

     

     

    D题,数据结构:线段树 Codefoces 266E

    题意:这里就不在描述了,题目很短= =

    解法:这个题和杭州邀请赛的C题是同一类型的。主要是对于 

    的计算。0<=k<=5,可以考虑直接展开(i-l+1)^k:

    k = 0: 1

    k = 1: i - l  + 1

    k = 2: i^2 - 2(l-1)i + (l-1)^2

    k = 3: i^3 - 3i^2(l-1) + 3i(l-1)^2 - (l-1)^3

    k = 4: i^4 - 4i^3(l-1) + 6i^2(l-1)^2 - 4i(l-1)^3 + (l-1)^4

    k = 5: i^5 - 5i^4(l-1) + 10i^3(l-1)^2 - 10i^2(l-1)^3 + 5i(l-1)^4 - (l-1)^5

     

    那么由于l-1项只与l有关,我们只需要用线段树维护:i^5ai , i^4ai, i^3ai, i^2ai, iai, ai的区间和。然后剩余的就是线段树的工作了。对于查询操作,可以直接将区间的上述和直接计算到,然后可以用按照二项式展开统一计算。

    #include <stdio.h>
    #include <string.h>
    
    #define maxn 100005
    #define lson(x) (x<<1)
    #define rson(x) (x<<1|1)
    #define md(x, y) ((x+y)>>1)
    typedef long long LL;
    #define MOD 1000000007
    LL val[6][maxn];
    LL ans[6];
    int C[6][6];
    
    struct Tree{
        LL f[6][maxn*4];
        LL v[maxn*4];
        void clear(){
            memset(f, 0, sizeof(f));
            memset(v, 0, sizeof(v));
        }
        void build(int c, int left, int right){
            if(left == right){
                scanf("%I64d", &v[c]);
                LL t = 1;
                for(int i = 0; i <= 5; i ++){
                    f[i][c] = t * v[c]%MOD;
                    t = t * left %MOD;
                }
                return ;
            }
            int m = md(left, right);
            build(lson(c), left, m);
            build(rson(c), m + 1, right);
            push_up(c);
        }
        void push_down(int c, int left, int right){
            if(v[c] == -1) return;
            int l = lson(c), r = rson(c);
            v[l] = v[r] = v[c];
            int m = md(left, right);
            for(int i = 0; i <= 5; i ++){
                f[i][l] = v[l] * (((val[i][m] - val[i][left-1])%MOD + MOD)%MOD)%MOD;
                f[i][r] = v[r] * (((val[i][right] - val[i][m])%MOD + MOD)%MOD)%MOD;
                f[i][c] = 0;
            }
            v[c] = -1;
        }
        void push_up(int c){
            int l = lson(c), r = rson(c);
            for(int i = 0; i <= 5; i ++){
                f[i][c] = (f[i][l] + f[i][r])%MOD;
            }
            v[c] = -1;
        }
        void update(int c, int l, int r, int left, int right, LL x){
            if(l <= left && right <= r){
                v[c] = x;
                for(int i = 0; i <= 5; i ++){
                    f[i][c] = x*(((val[i][right] - val[i][left-1])%MOD + MOD)%MOD)%MOD;
                }
                return ;
            }
            push_down(c, left, right);
            int m = md(left, right);
            if(r <= m) update(lson(c), l, r, left, m, x);
            else if(l > m) update(rson(c), l, r, m + 1, right, x);
            else{
                update(lson(c), l, m, left, m, x);
                update(rson(c), m + 1, r, m + 1, right, x);
            }
            push_up(c);
        }
        void query(int c, int l, int r, int left, int right, LL ans[]){
            if(l <= left && right <= r){
                for(int i = 0; i <= 5; i ++){
                    ans[i] = (f[i][c] + ans[i])%MOD;
                }
                return ;
            }
            push_down(c, left,right);
            int m = md(left, right);
            if(r <= m) query(lson(c), l, r, left, m, ans);
            else if(l > m) query(rson(c), l, r, m+1, right, ans);
            else {
                query(lson(c), l, m, left, m, ans);
                query(rson(c), m + 1, r, m + 1, right, ans);
            }
            push_up(c);
        }
    };
    Tree tree;
    void init(int n){
        for(int i = 1; i <= n; i ++){
            LL t = 1;
            for(int j = 0; j <= 5; j ++){
                val[j][i] = (val[j][i-1] + t)%MOD;
                t = (t * i)%MOD;
            }
        }
        C[0][0] = 1;
        C[1][1] = C[1][0] = 1;
        for(int i = 2; i <= 5; i ++){
            C[i][0] = 1;
            for(int j = 1; j <= i; j ++){
                C[i][j] = C[i-1][j] + C[i-1][j-1];
            }
        }
    }
    
    int main(){
        int n, m, l, r, x;
        char cmd[2];
        LL t;
        scanf("%d%d", &n, &m); getchar();
        init(n);
        tree.build(1, 1, n);
        for(;m --;){
            scanf("%s%d%d%d", cmd, &l, &r, &x);
            if(cmd[0] == '?'){
                memset(ans, 0, sizeof(ans));
                tree.query(1, l, r, 1, n, ans);
                LL result = 0; t = 1;
                for(int i = x, j = 0; i >=0; i --){
                    if(j&1) result = (result - ((ans[i]*t)%MOD)*C[x][j])%MOD;
                    else result = (result + ((ans[i]*t)%MOD)*C[x][j])%MOD;
                    t = (t * (l-1))%MOD; j ++;
                }
                printf("%I64d\n", (result+MOD)%MOD);
            }
            else tree.update(1, l, r, 1, n, x);
        }
        return 0;
    }
    

    E题:DP题,一个简单的树形DP, Codefoces 161D

    题意:题意比较简单,不在做描述了.

    解法:简单树形DP。

    答案分成两部分:

    1.a, b两个点的距离为k,且,a为b的祖先

    2.a, b两个点的距离为k,a,b分别在两颗不同的子树上。

    dp[i][k]表示,以i为根的子树上,与i的距离为k的节点个数。

    那么显然:dp[i][k] = sum{dp[s][k-1]}其中s是i的孩子节点。

    对于第一部分的答案,显然就是dp[i][k]

    对于第二部分的答案,是sum{dp[i][a]*dp[s][b]}其中s是当前待处理的孩子节点。

    #include <stdio.h>
    #include <string.h>
    #include <vector>
    using namespace std;
    #define maxn 50005
    
    vector<int> vec[maxn];
    int dp[maxn][505];
    long long ans;
    
    void dfs(int v, int f, int k){
        for(int i = 0; i <= k; i ++)
            dp[v][i] = 0;
        dp[v][0] = 1;
        for(int i = 0; i < vec[v].size(); i ++){
            int u = vec[v][i];
            if(u==f) continue;
            dfs(u, v, k);
            for(int j = 0; j < k; j ++){
                ans += dp[u][j] * dp[v][k - j - 1];
            }
            for(int j = 1; j < k; j ++){
                dp[v][j] += dp[u][j-1];
            }
        }
        ans += dp[v][k];
    }
    
    int main(){
        for(int n, k; scanf("%d%d", &n, &k)!=EOF; ){
            for(int i = 1; i <= n; i ++)
                vec[i].clear();
            for(int i = 1, x, y; i < n; i ++){
                scanf("%d%d", &x, &y);
                vec[x].push_back(y);
                vec[y].push_back(x);
            }
            ans = 0;
            dfs(1, 0, k);
            printf("%I64d\n", ans);
        }
        return 0;
    }
    

    F题,比较有意思的字符串题,这个是智商题,表示智商拙计。Codeforces 224D

    题意:给定两个串S和T,求是不是对于所有的Si,至少存在一个子串sub, sub是S的子串(不一定连续),Si属于sub,且sub==T.

    解法:对于S串的每个位置i,求出以i为终点的S1...Si与T1...Tt的最长公共子序列的长度l[i],

    然后求出以i为终点的Ss..Si+1Si与Tt...T1的最长公共子序列的长度r[i]。

    然后直接判断向左匹配的最大长度l[i]与向右匹配的最大长度r[i],是不是有l[i]+r[i]-1 >= t。

    由于只要求解长度,我们对于每个字符可以记录一个最长匹配长度,这样就可以做到O(n)的预处理匹配长度,然后可以做到O(n)的判断。

     

     1 #include <stdio.h>
     2 #include <string.h>
     3 #define maxn 200005
     4 
     5 char s[maxn], t[maxn];
     6 int l[maxn], r[maxn], pos[26];
     7 
     8 int main(){
     9     scanf("%s%s", s + 1, t + 1);
    10     int ls = strlen(s + 1), lt = strlen(t + 1);
    11 
    12     memset(pos, -1, sizeof(pos));
    13     for(int i = 1, j = 1; s[i]; i ++){
    14         if(t[j] && s[i]==t[j]){
    15             pos[s[i]-'a'] = j++;
    16         }
    17         l[i] = pos[s[i] - 'a'];
    18     }
    19     memset(pos, -1, sizeof(pos));
    20     for(int i = ls, j = 1; i > 0; i --){
    21         if(j <= lt && s[i]==t[lt - j + 1]){
    22             pos[s[i]-'a'] = j ++;
    23         }
    24         r[i] = pos[s[i]-'a'];
    25     }
    26     bool f = true;
    27     for(int i = 1; s[i]; i ++){
    28         if(l[i] == -1 || r[i] == -1 || l[i] + r[i] < lt + 1){
    29             f = false;
    30             break;
    31         }
    32     }
    33     puts(f? "Yes" : "No");
    34     return 0;
    35 }

     

     

  • 相关阅读:
    Cleaner Robot
    Lottery
    E. Three States
    cordova+vue-cli4构建app
    网站引导功能实现
    微信小程序双向绑定
    微信小程序html(wxml)传参
    什么是URL?网址的组成
    angular里使用vue/vue组件怎么在angular里用
    angular4 select 绑定(ngModel)对象
  • 原文地址:https://www.cnblogs.com/bootstar/p/3204702.html
Copyright © 2011-2022 走看看