• Codeforces Round #238 (Div. 1)


    感觉这场题目有种似曾相识感觉,C题还没看,日后补上。一定要坚持做下去。

    A
    Unusual Product

    题意:

    给定一个n*n的01矩阵,3种操作,

    1 i 将第i行翻转

    2 i 将第i列翻转

    3 询问矩阵第i行和第i列做向量乘法之和。

    分析:

    分析发现对于3的结果取决于对角线上1的个数num,即num%2,然后就很好做了,对于每次操作,只需要改变该行或该列后,对角线上仍然有多少个1.

    代码:

     1 #pragma comment(linker, "/STACK:16777216")
     2 #include <cstdio>
     3 #include <iostream>
     4 #include <cstring>
     5 #include <queue>
     6 #include <vector>
     7 #include <cmath>
     8 #define inf 0x0f0f0f0f
     9 #define in freopen("data.txt", "r", stdin);
    10 #define  pb push_back
    11 #define bug(x) printf("Line : >>>>%d
    ", (x));
    12 using namespace std;
    13 typedef unsigned short US;
    14 typedef long long LL;
    15 const int maxn = 1111;
    16 int vis[maxn];
    17 
    18 int main(){
    19 
    20     int n, q;
    21     scanf("%d", &n);
    22     int res = 0;
    23     for(int i = 0; i< n; i++) for(int j = 0; j < n; j++) {
    24         int t;
    25         scanf("%d", &t);
    26         if(i == j) vis[i] = t, res += t;
    27     }
    28     scanf("%d", &q);
    29    while(q--){
    30        int t, x;
    31        scanf("%d", &t);
    32        if(t != 3){
    33             scanf("%d", &x);
    34             vis[x] ^= 1;
    35             res += (vis[x] ? 1 : -1);
    36        }
    37        else{
    38         cout<<res%2;
    39        }
    40    }
    41    cout<<endl;
    42     return 0;
    43 }
    View Code

    B
    Toy Sum

    题意:

    共有1,2,3到10^6这么些个数首先选出n个数,x1~xn,要从剩下的数中选出若干数满足灯饰sum{xi-1| 1 <= i <= n} = sum {s-yi|1 <= i <= m}

    分析:

    xi-1和s-yi分别表示的数到两端的距离。

    那么对于xi如果离s一样的近的数没有被选中则优先选它,如果两端一样近的地方都选取了,先不管它。最后将能够选取的一样近的数都选取完毕后,再针对两端一样近的数都选了的情况,这时候也只要将两端一样近的从没选中的选进Y集合就行了。

    上面这样似乎才是标准解法,可是我是dfs暴力求解,加了些剪枝,也能过。

    我的代码:

     1 #pragma comment(linker, "/STACK:16777216")
     2 #include <cstdio>
     3 #include <iostream>
     4 #include <cstring>
     5 #include <bitset>
     6 #include <algorithm>
     7 #include <queue>
     8 #include <vector>
     9 #include <cmath>
    10 #define inf 0x0f0f0f0f
    11 #define in freopen("data.txt", "r", stdin);
    12 #define  pb push_back
    13 #define bug(x) printf("Line : >>>>%d
    ", (x));
    14 using namespace std;
    15 typedef unsigned short US;
    16 typedef long long LL;
    17 const int maxn = (int)1e6 + 100;
    18 LL a[maxn];
    19 bitset<maxn> vis;
    20 LL sum[maxn];
    21 int ok;
    22 vector<int> ans;
    23 int s = (int)1e6;
    24 
    25 void dfs(int x, LL sm) {
    26     if(ok) return;
    27     if(sm == 0) {
    28         ok = 1;
    29         return;
    30     }
    31     int k = upper_bound(a+1, a+x+1, sm) - a;
    32     k--;
    33     for(int i = k; i >= 1 && sum[i] >= sm; i--) {
    34         ans.pb(s-a[i]);
    35         dfs(i-1, sm-a[i]);
    36         if(ok) return;
    37         ans.pop_back();
    38     }
    39 }
    40 int main() {
    41 
    42     int n;
    43     scanf("%d", &n);
    44     LL tmp = 0;
    45     for(int i = 1; i <= n; i++) {
    46         int u;
    47         scanf("%d", &u);
    48         tmp += u-1;
    49         vis[u] = 1;
    50     }
    51 
    52 //    cout<<tmp<<endl;
    53     int cnt = 0;
    54     for(int i = s; i >= 1; i--)
    55         if(vis[i] == 0) {
    56             a[++cnt] = s-i;
    57 //            if(cnt <= 10)
    58 //            cout<<a[cnt]<<endl;
    59             sum[cnt] = sum[cnt-1] + s-i;
    60         }
    61     vis.reset();
    62     if(tmp == 0) {
    63         cout<< 1 <<endl;
    64         cout<< 1000000 << endl;
    65         return 0;
    66     }
    67     dfs(cnt, tmp);
    68     printf("%d
    ", ans.size());
    69 
    70     for(int i = 0; i < ans.size(); i++)
    71         printf("%d%c", ans[i], i == ans.size()-1 ? '
    ' : ' ');
    72     return 0;
    73 }
    View Code

    D
    Hill Climbing

    题意:

    每座山用一根垂直线段表示,有x,y两种属性,按照x递增给定n座山的xi和yi,每次在第i座山的时候只能够到达在视野范围内(这样说是没有问题的)的最右的一座山,然后两个人分别位于两座山上,问他们分别出发,沿着上面的原则确定的路线转移,直到两者到达同一座山。

    分析:

    首先要确定没座山能够到达的最右的一座山,除了最右的山没有可到达的山,每座山显然能到达另一座山,可以从右往左扫,建立单调栈,将第i座山与栈顶的斜率k1,栈顶与栈顶以下的一座山的斜率k2比较,如果k1 < k2将栈顶元素出栈。最后第i座山能够到达栈顶那座山,同时将i入栈。

    这样会得到一棵树,对于每个询问,只需要询问他们的lca就是了。

    注意:倍增法求lca的时候,应该在dfs子树的时候将fa[u][i]更新求出来。

    代码:

    #pragma comment(linker, "/STACK:16777216")
    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <bitset>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #include <cmath>
    #define inf 0x0f0f0f0f
    #define in freopen("data.txt", "r", stdin);
    #define  pb push_back
    #define esp 1e-6
    #define bug(x) printf("Line : >>>>%d
    ", (x));
    using namespace std;
    typedef unsigned short US;
    typedef long long LL;
    const int maxn = (int)1e5 + 100;
    struct Po {
        double x, y;
    } h[maxn];
    int st[maxn];
    vector<int> g[maxn];
    double cal(int x, int y) {
        return (h[x].y-h[y].y)/(h[x].x-h[y].x);
    }
    int fa[maxn][20], dep[maxn];
    double dblcmp(double x) {
        if(fabs(x) < esp) return 0;
        return x > 0 ? 1 : -1;
    }
    void dfs(int u, int f) {
        dep[u] = dep[f] + 1;
        fa[u][0] = f;
        for(int i = 1; i < 20; i++) {
            fa[u][i] = fa[fa[u][i-1]][i-1];
        }
        for(int i = 0; i < g[u].size(); i++) {
            int v = g[u][i];
            if(v == f)
                continue;
    //        cout<<v<<endl;
            dfs(v, u);
        }
    }
    int lca(int x, int y) {
        if(dep[x] < dep[y]) swap(x, y);
        int d = dep[x]-dep[y];
        for(int i = 0; i < 20; i++) if((d &(1<<i)))
                x = fa[x][i];
        if(x != y) {
            for(int i = 19; i >= 0; i--) if(fa[x][i] != fa[y][i])
                    x = fa[x][i], y = fa[y][i];
            x = fa[x][0];
        }
        return x;
    }
    int main() {
    
        int n, q;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            scanf("%lf%lf", &h[i].x, &h[i].y);
        }
        int top = 0;
        for(int i = n; i >= 1; i--) {
            while(top >= 2 && dblcmp(cal(i, st[top]) - cal(st[top], st[top-1])) < 0)
                top--;
            if(top) {
                g[st[top]].pb(i);
                g[i].pb(st[top]);
            }
            st[++top] = i;
        }
        dfs(n, 0);
        scanf("%d", &q);
        for(int i = 1; i <= q; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            printf("%d%c", lca(u, v), i == q ? '
    ' : ' ');
        }
        return 0;
    }
    View Code

    同样利用单调栈的一道题:HDU 5033 Building

  • 相关阅读:
    [csp-s模拟测试72] 简单的期望
    [csp-s模拟测试72] 简单的序列
    csp-s模拟测试70
    经验积累
    [csp-s模拟测试69] 回滚莫队
    [模板]主席树查前趋后继
    复习及学习计划
    错排公式
    csp-s模拟测试 56~65
    LIS LCS LCIS
  • 原文地址:https://www.cnblogs.com/rootial/p/3995778.html
Copyright © 2020-2023  润新知