zoukankan      html  css  js  c++  java
  • codeforces round #420 div2

    A:暴力枚举

    模拟

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 60;
    int n;
    int a[N][N];
    int main()
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i)
            for(int j = 1; j <= n; ++j)
                scanf("%d", &a[i][j]);
        for(int i = 1; i <= n; ++i)
            for(int j = 1; j <= n; ++j) if(a[i][j] != 1)
            {
                bool flag = false;
                for(int x = 1; x <= n; ++x) if(x != i)
                    for(int y = 1; y <= n; ++y) if(y != j)
                        if(a[i][j] == a[x][j] + a[i][y])
                        {
                            flag = true;
                            break;
                        }
                if(!flag)
                {
                    puts("No");
                    return 0;
                }
            }
        puts("Yes");
        return 0;
    }
    View Code

    B:其实我们发现,枚举纵坐标就能枚举出直线上所有的点,然后里面的价值可以O(1)算出,于是枚举纵坐标即可。

    模拟

    #include<bits/stdc++.h>
    using namespace std;
    int m, b;
    int main()
    {
        long long ans = 0;
        scanf("%d%d", &m, &b);
        for(long long  y = 0; y <= b; ++y)
        {
            long long x = m * b - m * y, 
                        tot = (1ll + x) * x / 2ll * (y + 1ll) + (1ll + y) * y / 2ll * (x + 1ll);
            ans = max(ans, tot);            
        }
        printf("%lld
    ", ans);
        return 0;
    }
    View Code

    C:这道题挺奥妙的。

    脑洞

    我们可以维护一个pq,当当前的值和pq的最小值不等时说明要调整。那么我们得问题就在于如何记录当前的值。然后发现这样不好做,因为调整后所有值都变了,那么我们换着一种思路,我们记录到第一个不符合的值之前有多少个符合的。当每次出现不符合的值时,把这个值赋成1,然后累加。每次删除时,我们只要减一,如果减到零了,说明需要调整,那么之前不符合的也符合了,所以之前那些值是没有用的,这样就完成了。

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 300010;
    int n, ans, cnt;
    priority_queue<int, vector<int>, greater<int> > q;
    int main()
    {
        scanf("%d", &n);
        bool flag = true;
        for(int i = 1; i <= 2 * n; ++i)
        {
            char opt[10]; scanf("%s", opt);
            if(opt[0] == 'a')
            {
                int pos; scanf("%d", &pos);
                if(!q.empty() && pos > q.top())
                    cnt = 1; //如果不行了 ,那么肯定需要排序,之前不算 
                else if(cnt)
                    ++cnt; //如果之前不行,现在行,计算可以不用调整的次数 
                q.push(pos);
            }
            if(opt[0] == 'r')
            {
                q.pop();
                if(cnt)
                {
                    --cnt; //累计在不行之前能减的次数 
                    if(cnt == 0) ++ans;
                }
            }
        }
        printf("%d
    ", ans);
        return 0;
    }
    View Code

    题解的方法是维护一个栈,每次remove时看是否和应该remove的值相等,相等就弹出,不等就ans+1,把所有元素弹出。这样为什么是对的呢?因为如果当前的数和栈顶相同,那么就是可以的,否则就需要调整。调整完了之后之前的数是有序的,也就不用再调整了,只有进来不可行的才需要调整。(我也理解的不是很透彻,还是上面那个方法直观)

    #include<bits/stdc++.h>
    using namespace std;
    int n, ans, now = 1;
    stack<int> st;
    int main()
    {
        scanf("%d", &n);
        for(int i = 1; i <= 2 * n; ++i)
        {
            char opt[10]; scanf("%s", opt);
            if(opt[0] == 'a')
            {
                int pos; scanf("%d", &pos);
                st.push(pos);
            }
            if(opt[0] == 'r')
            {
                if(!st.empty())
                {
                    if(now == st.top()) st.pop();
                    else
                    {
                        ans++;
                        while(!st.empty()) st.pop();
                    }
                }
                ++now;
            }
        }
        printf("%d
    ", ans);
        return 0;
    } 
    View Code

    D:这道题写的时候出题人说样例挂了,还有这种操作。。。

    最短路

    我们发现,只有横纵坐标有一个相差<=2时可以走过去,那么我们就可以考虑建图。这里要分类讨论一下边权的情况,还有终点是否亮。代码里都有了,然后跑最短路就行,可以用deque也可以用dijiestra,dijiestra跑得还挺快。记住不能把边存下来,有n^2条边。

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int, int> PII;
    const int N = 10010;
    struct data {
        int x, y;
    } a[N];
    int n, m, k;
    priority_queue<PII, vector<PII>, greater<PII> >q;
    int d[N], used[N], Q[N];
    bool flag = true;
    bool cp(data x, data y)
    {
        return x.x == y.x ? x.y < y.y : x.x < y.x;
    }
    void dijiestra()
    {  
        memset(used, 0, sizeof(used));
        for(int i = 2; i <= k; ++i) d[i] = 1 << 29;
        q.push(PII(0, 1));
        while(!q.empty())
        {
            PII x = q.top(); q.pop();
            int u = x.second;
            if(used[u]) continue;
            used[u] = 1;
            for(int i = 1; i <= k; ++i) if(i != u)
                if(abs(a[i].x - a[u].x) <= 2 || abs(a[i].y - a[u].y) <= 2)
                {
                    int w = 1;
                    if((abs(a[i].x - a[u].x) == 1 || abs(a[i].y - a[u].y) == 1) && (a[i].x - a[u].x == 0 || a[i].y - a[u].y == 0))
                        w = 0;
                    if(a[i].x == n && a[i].y == m && !flag) 
                    {    
                        w = 1;
                        if((abs(a[i].x - a[u].x) == 2 || abs(a[i].y - a[u].y) == 2) && (abs(a[i].x - a[u].x) >= 2 && abs(a[i].y - a[u].y) >= 2))
                            w = 1 << 29;                    
                    }
                    if(d[i] > d[u] + w)
                    {
                        d[i] = d[u] + w;
                        q.push(PII(d[i], i));
                    }
                }    
            }
    }
    int main()
    {
        scanf("%d%d%d", &n, &m, &k);
        for(int i = 1; i <= k; ++i)
            scanf("%d%d", &a[i].x, &a[i].y);
        sort(a + 1, a + k + 1, cp);
        if(a[k].x != n || a[k].y != m) 
        {
            flag = false;
            a[++k].x = n;
            a[k].y = m;
        }
        dijiestra();
        printf("%d
    ", d[k] >= 1 << 29 ? -1 : d[k]);
        return 0;
    }
    View Code

    E:昨天晚上以为这道题组合搞搞就行了。。。

    矩阵快速幂

    dp:dp[i][x]=dp[i-1][x-1]+dp[i-1][x]+dp[i-1][x+1] 边界不讨论了。

    然后这是标准的矩阵快速幂形式,那么对于每条线段构造矩阵,最后一条线段的终点要设成k,初值dp[0][0]=1,输出dp[k][0]。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 110;
    const ll mod = 1000000007;
    struct mat {
        ll a[16][16];
    } l;
    struct data {
        ll a, b;
        int c;
    } a[N];
    int n;
    ll k;
    mat operator * (mat A, mat B)
    {
        mat ret; memset(ret.a, 0, sizeof(ret.a));
        for(int i = 0; i <= 15; ++i)
            for(int j = 0; j <= 15; ++j)
                for(int k = 0; k <= 15; ++k)
                    ret.a[i][j] = (ret.a[i][j] + A.a[i][k] * B.a[k][j] % mod) % mod;
        return ret;
    }
    mat power(mat x, ll t)
    {
        mat ret; memset(ret.a, 0, sizeof(ret.a));
        for(int i = 0; i <= 15; ++i)
            ret.a[i][i] = 1;
        for(; t; t >>= 1, x = x * x) if(t & 1) ret = x * ret;
        return ret;
    }
    int main()
    {
        cin >> n >> k;
        for(int i = 1; i <= n; ++i)
            scanf("%lld%lld%d", &a[i].a, &a[i].b, &a[i].c);
        a[n].b= k;
        l.a[0][0] = 1;
        for(int i = 1; i <= n; ++i)
        {
            mat x; memset(x.a, 0, sizeof(x.a));
            for(int j = 0; j <= a[i].c; ++j)
            {
                if(j > 0)
                    x.a[j][j - 1] = 1;
                x.a[j][j] = 1;
                if(j < a[i].c)
                    x.a[j][j + 1] = 1;
            }
            l = power(x, a[i].b - a[i].a) * l;
        }
        printf("%lld
    ", l.a[0][0]);
        return 0;
    }
    View Code
  • 相关阅读:
    宁波工程学院2020新生校赛C
    宁波工程学院2020新生校赛B
    宁波工程学院2020新生校赛A -恭喜小梁成为了宝可梦训练家~(水题)
    POJ 1611
    牛客算法周周练11E
    牛客算法周周练11C
    牛客算法周周练11A
    CodeForces 1176C
    CodeForces 445B
    UVALive 3027
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7079439.html
Copyright © 2011-2022 走看看