【Codeforces Round #541 (Div. 2)】

too naive,,, cf

A

水题
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
int w1,h1,w2,h2;
int ans = 0;
main(){
    cin>>w1>>h1>>w2>>h2;
    int ans = 0;
    ans += (h1+h2)*2 + max(w1,w2)*2+4;
    cout<<ans;
}

B

给你若干次比赛中途的比分情况,问最多的可能出现的平局比分。 模拟这个过程即可。。然而shabi如我却wa飞了
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
int a[10005],b[10005],n;
int ans;
main(){
    cin>>n;
    for(int i=1;i<=n;i++) {
        cin>>a[i]>>b[i];
    }
    a[0] = -1; b[0] = -1;
    for(int i=0;i<n;i++) {
        if(a[i]==a[i+1]&&b[i]==b[i+1]) continue;
        int ao = a[i]; int at = a[i+1];
        int bo = b[i]; int bt = b[i+1];
        if(ao>bo) swap(ao,bo),swap(at,bt);
        if(ao==bo) ans += min(at,bt)-ao;
        else if(at>=bo) ans += min(bt-bo+1,at-bo+1);
    }
    cout<<ans;
}

C

给你n 1e5个人的ai,围成一个环使得 ( \sum 相邻的ai之差的绝对值 ) 最小。 ACM的一道原题?直接贪心让最大的放中间,然后一个一个临着放。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
int n;
int a[105];
int b[105];
int main(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    int L = 0;int R = 1e9,mid,ans;
    sort(a+1,a+1+n,greater<int>());
    int ml = (n/2); int mr = (n/2)+1;
    for(int i=1;i<=n;i++) {
        if(i&1) b[mr++] = a[i]; else b[ml--] = a[i];
    }
    for(int i=1;i<=n;i++) cout<<b[i]<<' ';
}

D

给你两个长度分别为 n,m的正整数序列 a,b。以矩阵形式给出所有 ai 和 bj(1≤i≤n,1≤j≤m) 的大小关系(>,<,=)。构造符合条件的 a 和 b序列,且 a,b 中最大元素尽量小。无解,输出No。 其实转化之后就只有<和=,我们把所有=的节点利用并查集合并在一起。然后利用剩下的跑topsort就可以了。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 5e3+5;

string ss[1005];
int n,m;
int a[maxn],b[maxn],tot;
int dis[maxn];
bool fk;
int f[maxn];
int dd[maxn];
int fa[maxn];
vector<int>ve[maxn];
queue<int>q;
int gf(int x) { return fa[x] == x?x:fa[x]=gf(fa[x]); }
int rd[maxn];
void dayu(int x,int y) {
    x = gf(x); y = gf(y);
    if(x==y) {
        fk = 1; return ;
    }
    ve[y].push_back(x),rd[x]++;
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++) a[i] = ++tot;
    for(int j=1;j<=m;j++) b[j] = ++tot;
    for(int i=1;i<=tot;i++) fa[i] = i;
    for(int i=1;i<=n;i++) {
        cin>>ss[i];
        for(int j=1;j<=m;j++) {
            if(ss[i][j-1]=='=') {
                int x = gf(a[i]); int y = gf(b[j]);
                if(x!=y) fa[x] = y;
            }
        }
    }
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=m;j++) {
            if(ss[i][j-1]=='>') dayu(a[i],b[j]);
            else if(ss[i][j-1]=='<') dayu(b[j],a[i]);
            if(fk) break;
        }
        if(fk) break;
    }
    if(fk) puts("No");
    else{
        int OWO = 0; int OYO = 0;
        for(int i=1;i<=tot;i++) {
            if(gf(i)==i)
            {
                OWO++;
                if(!rd[i]) q.push(i),f[i]=1;
            }
        }
        while(q.size()) {
            OYO++;
            int x = q.front(); q.pop();
            for(auto y:ve[x]) {
                f[y] = max(f[y],f[x]+1);
                if(--rd[y]==0) q.push(y);
            }
        }
        if(OWO!=OYO) {
            puts("No"); return 0;
        }
        puts("Yes");
        for(int i=1;i<=n;i++) printf("%d ",f[gf(a[i])]);
        puts("");
        for(int i=1;i<=m;i++) printf("%d ",f[gf(b[i])]);
    }
}

E 补

连续地每次一个串插入到另一个串的缝之间(即所有缝隙中有另一个串),n1e5,求最后最长的连续同字母子串长度。 对于一个串插入到另一个缝中,显然只有边缘是可以根据上一次的答案再更新的,否则是独立的计算答案。 那么三种情况, 1.左串,则与原本的x串连续处合并起来变成一个更长x串。 2.左侧右侧都是x串中间间隔,那么就是1+左侧长+右侧长(如果原串有x) 3.左侧x,右侧y,考虑是否有1+x和1+y更新即可。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;
int n;
char ss[100005];
int a[30],b[30],p1,p2;
int len;
void upd(int &x,int y) {
    x = max(x,y);
}
void calc() {
    memset(a,0,sizeof a);
    len = strlen(ss+1); p1 = 0; p2 = 0;
    p1 = 1; while(p1<len&&ss[p1+1]==ss[1]) p1++;
    p2 = 1; while(p2<len&&ss[len-p2]==ss[len]) p2++;
    for(int i=1,cc=1;i<len;i++) {
        if(ss[i]!=ss[i+1]) upd(a[ss[i]-'a'+1],cc),cc=1;
        else cc++;
    }
    upd(a[ss[len]-'a'+1],p2);
}
int main() {
    scanf("%d",&n);
    scanf("%s",&ss[1]);
    calc();
    for(int i=1;i<=26;i++) b[i] = a[i];
    for(int i=1;i<n;i++) {
        scanf("%s",&ss[1]);
        calc();
        if(p1==len) {
            int x = ss[1]-'a'+1;
            b[x]= a[x]*b[x]+b[x]+a[x];
            for(int j=1;j<=26;j++) {
                if(j==x) continue;
                if(b[j]) b[j] = 1; else b[j] = 0;
            }
        } else if(ss[1]==ss[len]) {
            int x = ss[1]-'a'+1;
            if(b[x]) b[x] = p1 + p2 + 1;
            for(int j=1;j<=26;j++) {
                if(j==x) continue;
                if(b[j]) b[j] = 1; else b[j] = 0;
            } 
        } else {
            int x = ss[1]-'a'+1; int y = ss[len]-'a'+1;
            if(b[x]) b[x] = p1 + 1; if(b[y]) b[y] = p2+1;
            for(int j=1;j<=26;j++) {
                if(j==x||j==y) continue;
                if(b[j]) b[j] = 1; else b[j] = 0;
            }           
        }
        for(int i=1;i<=26;i++) upd(b[i],a[i]);
    }
    int orz = 0;
    for(int i=1;i<=26;i++) {
        orz = max(orz,b[i]);
    }
    printf("%d",orz);
}

F

并查集模拟即可
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
vector<int>ve[300005];
int n;
int tot;
int fa[300005];
int gf(int x) { return x==fa[x]?x:fa[x]=gf(fa[x]); }
void dfs(int x) {
    if(x<=n) printf("%d ",x);
    for(auto p:ve[x]) {
        dfs(p);
    }
}
int main(){
    cin>>n;
    tot = n;
    for(int i=1;i<=n;i++) fa[i] = i;
    for(int i=1;i<n;i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        x = gf(x); y = gf(y);

        if(x!=y) {
            ++tot;fa[tot]=tot;
            fa[x]=fa[y]=tot;
            ve[tot].push_back(x);
            ve[tot].push_back(y);
        }
    }
    dfs(tot);
}

G补

一行1e7的多米诺骨牌,推倒某一个要花钱,要么左推要么右推,可以推倒一些别的多米诺骨牌。求最小花费推倒一切。 主要是考虑消除掉左推和右推带来的后效性。先用单调栈处理掉左边第一个不能推到的骨牌和右边第一个不能推倒的骨牌。考虑右转移到左,转移的时候先考虑对于左边最后一个可以推倒的骨牌的dp转移贡献,然后再考虑通过右边第一个不能推倒的骨牌转移该骨牌向右推即可。
#include<stdio.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#include<cstring>
#define int long long
using namespace std;
const int maxn = 10000005;
int n,m;
int dp[maxn],L[maxn],R[maxn],RF[maxn],H[maxn],C[maxn];
vector<int>KH[250005],KC[250005];

main() {
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++) {
        int K; scanf("%lld",&K);
        KH[i].resize(K); KC[i].resize(K);
        for(int j=0;j<K;j++) {
            scanf("%lld",&KH[i][j]);
        }
        for(int j=0;j<K;j++) {
            scanf("%lld",&KC[i][j]);
        }
    }
    int Q; int tot = 0;
    scanf("%lld",&Q);
    memset(dp,0x3f,sizeof dp);
    for(int i=1;i<=Q;i++) {
        int id,mu; scanf("%lld%lld",&id,&mu);
        int ss = KH[id].size();
        for(int j=0;j<ss;j++) {
            ++tot;
            H[tot] = KH[id][j];
            C[tot] = KC[id][j]*mu;
            L[tot] = tot-1;
            while(L[tot]>=1&&tot-L[tot]<H[tot]) L[tot] = L[L[tot]];
        }
    }
    dp[m+1] = 0;
    for(int i=m;i>=1;i--) {
        RF[i] = dp[i+1];
        R[i] = i+1;
        while(R[i]<=m&&R[i]-i<H[i]) {
            RF[i] = min(RF[i],RF[R[i]]);
            R[i] = R[R[i]];
        }
        dp[L[i]+1] = min(dp[L[i]+1],dp[i+1]+C[i]);
        dp[i] = min(dp[i],RF[i]+C[i]); 
    }
    printf("%lld",dp[1]);
}
posted @ 2019-03-06 13:32  Newuser233  阅读(3)  评论(0编辑  收藏  举报