【CF】Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 1)

orz orz orz CF

A1 A2

给你n个点,m个糖,告诉你这个糖要从x点拿到y点,每次经过一个城市只能拿一个糖,但可以放任意数量的糖 问你从任意一个点开始走,最少要走几步,只能从1->2->3->4……->n->1 同一道题数据范围不同。。用同一份代码都能A。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<queue>
#include<stack>
#include<vector>

using namespace std;
int n,m; 
int jl(int x,int y) {
    if(x<=y) return y-x;
    return y+n-x;
}
int CNT[5005],ZJ[5005];
int ans;
int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) ZJ[i] = n;
    for(int i=1;i<=m;i++) {
        int a,b; scanf("%d%d",&a,&b);
        CNT[a]++; ZJ[a] = min(ZJ[a],jl(a,b));
    }
    for(int i=1;i<=n;i++) {
        ans = 0;
        if(CNT[i]) ans =  max(ans,(CNT[i]-1)*n+ZJ[i]);
        for(int j=1;j<=n;j++) {
            if( (!CNT[j])||(i==j) ) continue;
            ans = max(ans,jl(i,j)+(CNT[j]-1)*n + ZJ[j] );
        }
        printf("%d ",ans);
    }
}

B

给了你一个假贪心,你要构造一组数据把它卡掉,并且使得这组数据的结果和贪心的结果之差恰好为k. 随便怎么构都可以啦orz.有一种方法是前面全构造0然后又加一个-1之后全放正数。这样假贪心的结果一定是后面正数的总和,然后我们的真贪心的结果是总长度×(正数总和-1),稍微构造一下就可以了。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<queue>
#include<stack>
#include<vector>
#define int long long
using namespace std;
int k;
int CD;
bool ok(int X,int cd) {
    int chang = cd + CD;
    if(chang>2000) return 0;
    X++;
    if(X>((int)1e6)*CD) return 0;
    printf("%I64d\n",chang);
    for(int i=1;i<cd;i++) printf("0 ");
    printf("-1 ");
    for(int i=1;i<=CD;i++) {
        printf("%I64d ",min(1000000LL,X));
        X -= min(1000000LL,X);
    }
    return 1;
}
main() {
    cin>>k;
    for(int cd=1;cd<=1999;cd++) {
    int K = cd+k;
        CD = cd;
        for(int i=1;1ll*i*i<=K;i++) {
            if(K%i) continue;
            if(ok(i,K/i)) {
                return 0;
            }
            if(ok(K/i,i)) {
                return 0;
            }
        }
    }
    puts("-1");
}

C

长度为1,2,3,4的二进制串一共有30个,除了0011,0101,1110,1111之外,每一个都对应着一个字母。 现在给定一个串S,对于每一个i,询问S[1,i]中的所有子串中,本质不同的对应着一个英文字母串的拆分方案数。 考虑其实两个问题,首先对于一种子串询问拆分的方案,其次对于本质相同的子串答案只计算贡献一次。 第一问f[i][j]表示区间[i,j]可以拆分的。枚举最后的字母是什么就可以了。 第二问trie,SAM,hash啥的都可以干
#include<stdio.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>

using namespace std;
const int mod = 1e9+7;
int add(int x,int y) { x+=y; return x>=mod?x-mod:x; }
int sub(int x,int y) { x-=y; return x<0?x+mod:x; }
int mul(int x,int y) { return 1ll*x*y%mod; }
int m;
int ch[4500005][2],tot=1;
int f[3005][3005];
int a[3005],ans;
bool PD(int l,int r) {
    if(r-l+1<4) return 1;
    if(a[l]==0&&a[l+1]==0&&a[l+2]==1&&a[l+3]==1) return 0;
    if(a[l]==0&&a[l+1]==1&&a[l+2]==0&&a[l+3]==1) return 0;
    if(a[l]==1&&a[l+1]==1&&a[l+2]==1&&a[l+3]==0) return 0;
    if(a[l]==1&&a[l+1]==1&&a[l+2]==1&&a[l+3]==1) return 0;
    return 1;
}
int main() {
    scanf("%d",&m);
    for(int i=1;i<=m;i++) scanf("%d",&a[i]);
    for(int i=1;i<=m;i++) {
        for(int j=i;j>=(max(i-3,1));j--) {
            if(PD(j,i)) {
                f[j][i] = add(f[j][i],1);
                for(int k=j-1;k>=1;k--) {
                    f[k][i] = add(f[k][i],f[k][j-1]);
                }
            }
        }
        int o = 1;
        for(int j=i;j>=1;j--) {
            if(!ch[o][a[j]]) {
                ch[o][a[j]] = ++tot;
                ans = add(ans,f[j][i]);
            }
            o = ch[o][a[j]];
        }
        printf("%d\n",ans);
    }

}

D

把一个数组分成不相交的若干段,使得每一段中出现了恰好1次的数的个数至多是k个。 求划分方案数。 看这位大佬的ba无梦之梦
/*
if ai first v = 1 
ai last = -1
ai second last = 0
S[i] = \sum vj (j<=i)
dp[i] = \sum j(0,i-1): dp[j] (Sj>=Si-k)

*/
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>

using namespace std;
const int mod = 998244353;
const int maxn = 1e5+5;
const int maxk = 350;
int add(int x,int y) { x+=y; return x>=mod?x-mod:x; }
int sub(int x,int y) { x-=y; return x<0?x+mod:x; }
int mul(int x,int y) { return 1ll*x*y%mod; }
void upd(int &x,int y) { x=add(x,y); }
int blk,n,k,ks,blo[maxn];
int MX[maxk],tag[maxk];
int S[maxk][maxn],sv[maxn],L[maxk],R[maxk];
int dp[maxn];
int V[maxn];
void build(int o) {
    int mixx = 0x3f3f3f3f; int maxx = -0x3f3f3f3f;
    for(int i=L[o];i<=R[o];i++) {
        mixx = min(mixx,sv[i]);
        maxx = max(maxx,sv[i]);
    }
    MX[o] = maxx-mixx;
    tag[o] += mixx;
    fill(S[o],S[o]+MX[o]+2,0);
    for(int i=L[o];i<=R[o];i++) {
        sv[i] -= mixx;
        upd(S[o][sv[i]],dp[i]);
    }
    for(int i=MX[o];i>=0;i--) upd(S[o][i],S[o][i+1]);
}
void change1(int o,int l,int r,int x) {
    for(int i=l;i<=r;i++) sv[i] = sv[i]+x;
}
void modify(int l,int r,int x) {
    if(x==V[l]) return;
    int orz = x-V[l];
    V[l] = x;
    if(blo[l]==blo[r]) {
        change1(blo[l],l,r,orz);
        return;
    }
    for(int i=blo[l]+1;i<blo[r];i++) tag[i]+=orz;
    change1(blo[l],l,R[blo[l]],orz); 
    build(blo[l]);
    change1(blo[r],L[blo[r]],r,orz);
}
int nt[maxn],lst[maxn];
int query(int o,int V) {
    V -= tag[o];
    if(V>MX[o]) return 0;
    if(V<0) return S[o][0];
    return S[o][V];
}
int main() {
    scanf("%d%d",&n,&k);
    ks = 1; blk = sqrt(n);
    for(int i=1;i<=n;i++) {
        blo[i] = ks;
        R[ks] = i;
        if(i%blk==0) ks++,L[ks]=i+1;
    }
    if(n%blk==0) ks--;
    for(int i=1;i<=n;i++) {
        int val; scanf("%d",&val);
        nt[i] = lst[val]; lst[val] = i;
        int a = nt[i]; int b = nt[nt[i]];
        sv[i] = sv[i-1]; if(blo[i]!=blo[i-1]) sv[i] += tag[blo[i-1]];
        if(a) modify(a,i,-1);
        if(b) modify(b,i,0);
        sv[i]++;V[i] = 1;
        if(sv[i]<=k) dp[i] = 1;
        for(int j=1;j<blo[i];j++) upd(dp[i],query(j,sv[i]-k));
        for(int j=L[blo[i]];j<i;j++) if(sv[j]>=sv[i]-k) upd(dp[i],dp[j]);

        if(i==R[blo[i]]) build(blo[i]);
    }
    printf("%d",dp[n]);
}

E

有趣地构造。强制1当根,然后找出每个点的siz.siz从小到大排序之后,对于每个点当父亲的情况,从前面siz比自己小的并且没有父亲的点中选,考虑二分不断地找出所有可以当他儿子的点,每一次log都一定有一个点找到了父亲,O(nlogn)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<set>
#define pr pair<int,int>
#define fi first
#define se second
using namespace std;
const int maxn = 505;
int fa[maxn],qe[maxn];
int n,sz[maxn];
void fl() {
    fflush(stdout);
}
void pt(int x) {
    printf("%d\n",x);
}
int yo() {
    fl();
    int x; scanf("%d",&x);
    return x;
}
pr a[maxn];
int ST[maxn];
set<int>se;
int GAOIT(int L,int R,int owo) {
    pt(R-L+1);
    for(int i=L;i<=R;i++) pt(ST[i]);
    pt(1); pt(1);
    pt(owo);
    fl();
    return yo();
}
int main() {
    n = yo();
    sz[1] = n;
    a[1] = pr(n,1);
    for(int i=2;i<=n;i++) {
        pt(1); pt(1);
        pt(n-1);
        for(int j=2;j<=n;j++) {
            pt(j);
        }
        pt(i);
        fl();
        sz[i] = yo();
        a[i] = pr(sz[i],i);
    }
    sort(a+1,a+1+n);
    for(int i=1;i<=n;i++) {
        int tp = 0;
        for(auto o:se) {
            ST[++tp] = o;
        }
        for(int j=1;j<=tp;) {
            if(!GAOIT(j,tp,a[i].se)) break;
            int L = j; int R = tp; int mid , ans = 0;
            while(L<=R) {
                int mid = (L+R)>>1;
                if(GAOIT(L,mid,a[i].se)) ans = mid , R = mid - 1;
                else L = mid + 1;
            }
            fa[ST[ans]] = a[i].se;
            se.erase(ST[ans]);
            j = ans + 1;
        }
        se.insert(a[i].se);
    }
    puts("ANSWER");
    for(int i=2;i<=n;i++) {
        printf("%d %d\n",i,fa[i]);
    }
}
posted @ 2019-03-08 13:15  Newuser233  阅读(10)  评论(0)    收藏  举报