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\n", 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\n", 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\n", 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\n", 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\n", l.a[0][0]);
    return 0;
}
View Code

 

posted @ 2017-06-26 10:42  19992147  阅读(129)  评论(0编辑  收藏  举报