2020牛客暑期多校训练营(第五场)

A-Portal

我们只用维护一个传送门,因为每次我们使用传送门的时候都是在当前位置设一个,然后跳过去.
所以我们定义状态 f [ i ] f[i] f[i]表示传送门在 i i i的最小花费时间即可.
总复杂度为 O ( n 3 + k ⋅ n 2 ) O(n^3+k\cdot n^2) O(n3+kn2).

#include<bits/stdc++.h>
#define debug(a) {for(int i=1;i<=n;i++) printf("%lld ",a[i]); puts("");}
using namespace std;
typedef long long ll;
const int N=310;
const ll inf=(ll)1e14;

int n,m,q;
ll a[N][N],f[N],g[N];
void qr(int &x) {scanf("%d",&x);}

void move(int x,int y) {
    for(int i=1;i<=n;i++) g[i]=f[i]+min(a[x][y],a[i][y]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            g[j]=min(g[j],f[i]+min(a[x][j],a[i][j])+min(a[j][y],a[i][y]));
    for(int i=1;i<=n;i++) f[i]=g[i];
}

int main() {
    qr(n); qr(m); qr(q); 
    memset(a,63,sizeof a);
    for(int i=1,x,y,z;i<=m;i++) qr(x),qr(y),qr(z),a[x][y]=a[y][x]=min(a[x][y],(ll)z);
    for(int i=1;i<=n;i++) a[i][i]=0;
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                a[i][j]=min(a[i][j],a[i][k]+a[k][j]);
    
    memset(f,63,sizeof f); f[1]=0;
    int last=1;
    while(q--) {
        int x,y; qr(x); qr(y);
        move(last,x); 
        // debug(f);
        move(x,y);
        // debug(f); 
        last=y;
    }
    cout<<f[last]<<endl; return 0;
}

B-Graph

d [ i ] d[i] d[i]表示根到 i i i的边权异或值.
可以发现无论怎样加边删边, x , y x,y x,y之间加边的大小恒为 d [ x ] xor d [ y ] d[x]\text{xor}d[y] d[x]xord[y].
然后就是一个 b o r u v k a boruvka boruvka 板子了~~

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;

void qr(int &x) {scanf("%d",&x); }

int n,d[N];  ll ans;
struct edge{int y,next,d; } a[N*2]; int len,last[N];
void ins(int x,int y,int z) {a[++len]=(edge){y,last[x],z}; last[x]=len;}

void DFS(int x,int fa) {
    for(int k=last[x],y;k;k=a[k].next) 
        if((y=a[k].y)^fa) {
            d[y]=d[x]^a[k].d;
            DFS(y,x);
        }
}

//Trie
int tr[N*30][2],tot;
void clear() {memset(tr+1,0,sizeof(tr[0])*tot); tot=1; }
void ins(int x) {
    int p=1;
    for(int i=29;i>=0;i--) {
        int c=x>>i&1;
        if(!tr[p][c]) tr[p][c]=++tot;
        p=tr[p][c];
    }
}
int find(int x) {
    int p=1,s=0;
    for(int i=29;i>=0;i--) {
        int c=x>>i&1;
        if(!tr[p][c]) s|=1<<i,p=tr[p][!c];
        else p=tr[p][c];
    }
    return s;
}

int u[N],v[N];
void solve(int x,int l,int r) {
    if(x==-1||l>r) return ;
    int y=0,z=0,mn=2e9; clear();
    for(int i=l;i<=r;i++) 
        if(d[i]>>x&1) u[++y]=d[i],ins(d[i]);
        else v[++z]=d[i];
    for(int i=1;i<=z;i++) mn=min(mn,find(v[i]));
    if(y&&z) ans+=mn;
    // ,cout<<x<<' '<<l<<' '<<r<<' '<<mn<<endl;
    for(int i=l,j=1;i<l+y;i++) d[i]=u[j++];
    for(int i=l+y,j=1;i<=r;i++) d[i]=v[j++];
    solve(x-1,l,l+y-1); solve(x-1,l+y,r);
}

int main() {
    qr(n);
    for(int i=1,x,y,z;i<n;i++) qr(x),qr(y),qr(z),ins(x,y,z),ins(y,x,z);
    DFS(0,-1); 
    // for(int i=0;i<n;i++) printf("%d ",d[i]); puts("");
    solve(29,0,n-1); cout<<ans; return 0;
}

C-Easy

想了一个 O ( k n 2 m 2 ) O(kn^2m^2) O(kn2m2)的做法就不知所措…
b r z brz brz 优化成了 O ( k n m ) O(knm) O(knm).
定义 f [ i ] [ j ] f[i][j] f[i][j] 表示 A A A i i i个, B B B j j j个的方案数, g g g为上一次的状态.
则有
s [ i ] [ j ] = ∑ x = 1 i ∑ y = 1 j g [ i ] [ j ] s[i][j]=\sum_{x=1}^i \sum_{y=1}^j g[i][j] s[i][j]=x=1iy=1jg[i][j]
f [ i ] [ j ] = ∑ k = 1 min ⁡ ( i , j ) s [ i − k ] [ j − k ] f[i][j]=\sum_{k=1}^{\min(i,j)} s[i-k][j-k] f[i][j]=k=1min(i,j)s[ik][jk]
可以发现 g [ x ] [ y ] g[x][y] g[x][y] f [ i ] [ j ] f[i][j] f[i][j]的贡献正好为 min ⁡ ( i − x , j − y ) \min(i-x,j-y) min(ix,jy)次.
所以 O ( n m k ) O(nmk) O(nmk).

正解是生成函数.(设 n ≤ m n\le m nm)
先列出总方案数的生成函数:
( ( x + x 2 + x 3 + . . . + x n ) ⋅ ( y + y 2 + y 3 + . . . . + y m ) ) k \left( (x+x^2+x^3+...+x^n)\cdot (y+y^2+y^3+....+y^m) \right)^k ((x+x2+x3+...+xn)(y+y2+y3+....+ym))k.
那么方案数为 x n y m x^ny^m xnym的系数.

抽出一位看: ( x + x 2 + x 3 + . . . + x n ) ⋅ ( y + y 2 + y 3 + . . . . + y m ) (x+x^2+x^3+...+x^n)\cdot (y+y^2+y^3+....+y^m) (x+x2+x3+...+xn)(y+y2+y3+....+ym).
一个 x i y j x^iy^j xiyj的系数应该是 min ⁡ ( i , j ) \min(i,j) min(i,j),由上面的暴力我们可以想到乘上 ( 1 + x y + x 2 y 2 + . . . + x n − k y n − k ) (1+xy+x^2y^2+...+x^{n-k}y^{n-k}) (1+xy+x2y2+...+xnkynk),这样系数就正好了.

( ( x + x 2 + x 3 + . . . + x n ) ⋅ ( y + y 2 + y 3 + . . . . + y m ) ⋅ ( 1 + x y + x 2 y 2 + . . . + x n − k y n − k ) ) k \left( (x+x^2+x^3+...+x^n)\cdot (y+y^2+y^3+....+y^m) \cdot (1+xy+x^2y^2+...+x^{n-k}y^{n-k}) \right)^k ((x+x2+x3+...+xn)(y+y2+y3+....+ym)(1+xy+x2y2+...+xnkynk))k.的 x n y m x^ny^m xnym的系数即答案.

我们枚举 i i i表示 ( x y ) (xy) (xy)的总指数和,然后剩下 x n − i y m − i x^{n-i}y^{m-i} xniymi,我们应用插板法可以得出答案…

int T,n,m,k;
ll ans,jc[N],inv[N];
ll power(ll a,ll b=mod-2) {
    ll c=1;
    while(b) {
        if(b&1) c=c*a%mod;
        b /= 2; a=a*a%mod;
    }
    return c;
}
ll C(int x,int y) {return jc[x]*inv[y]%mod*inv[x-y]%mod;}

int main() {
    m=N-1; jc[0]=1; for(int i=1;i<=m;i++) jc[i]=jc[i-1]*i%mod;
    inv[m]=power(jc[m]); for(int i=m;i;i--) inv[i-1]=inv[i]*i%mod;
    qr(T); while(T--) {
        qr(n); qr(m); qr(k); ans=0; if(n>m) swap(n,m);
        for(int i=0;i<=n-k;i++) ans+=C(i+k-1,i)*C(n-i-1,k-1)%mod*C(m-i-1,k-1)%mod;
        pr2(ans%mod); 
    }
    return 0;
}

D-Drop Voicing

操作1可以看作 1 ∼ n − 1 1\sim n-1 1n1的旋转.
操作2可以看作 1 ∼ n 1\sim n 1n的旋转.
所以一次操作1 + 若干次操作2 可以让一个数到达任意位置.
然后就是求最长上升子序列的长度啦~~

int n,ans,a[N],sta[N],top;

int solve(int *b) {
    sta[top=0]=0;
    for(int i=1;i<=n;i++) {
        if(sta[top]<b[i]) sta[++top]=b[i];
        else *lower_bound(sta+1,sta+top+1,b[i])=b[i];
    }
    return top;
}

int main() {
    qr(n);
    for(int i=1;i<=n;i++) qr(a[i]),a[i+n]=a[i];
    ans=n; for(int i=0;i<n;i++) ans=min(ans,n-solve(a+i));
    pr2(ans); return 0;
}

E-Bogo Sort

容易发现是求一个环长的 l c m lcm lcm.

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;

int prime[N],tot,v[N],id[N],n,mx[N],p[N];
bool vis[N];

struct NUM {
    int len,a[N];
    NUM() {memset(a,0,sizeof a); len=a[1]=1; }
    void jump(int i) {a[i+1]+=a[i]/10; a[i]%=10;}
    void operator *=(int x) {
        for(int i=1;i<=len;i++) a[i]*=x;
        for(int i=1;i<=len;i++) jump(i);
        while(a[len+1]) jump(++len);
    }
    void output() {
        for(int i=min(len,n);i>0;i--) putchar(a[i]+'0');
        puts("");
    }
}f ;

void div(int x) {
    while(x>1) {
        int y=v[x];
        mx[id[y]]=max(mx[id[y]],y);
        x /= y;
    }
}

int main() {
    cin>>n ; 
    for(int i=2;i<=n;i++) {
        if(!v[i]) prime[++tot]=v[i]=i,id[i]=tot;
        for(int j=1,k;(k=i*prime[j])<=n;j++) {
            if(i%prime[j]==0) {id[k]=id[prime[j]]; v[k]=v[i]*prime[j]; break; }
            else v[k]=prime[j]; 
        }
    }
    for(int i=1;i<=n;i++) scanf("%d",&p[i]);
    for(int i=1;i<=n;i++) if(!vis[i]) {
        int x=i,tot=0;
        while(!vis[x]) vis[x]=1,tot++,x=p[x];
        div(tot);
    }
    for(int i=1;i<=tot;i++) if(mx[i]) f*=mx[i];
    f.output(); return 0;
}

F-DPS

模拟

#include<bits/stdc++.h>
using namespace std;
const int N=110;

int n,d[N],mx;

int main() {
    cin>>n;
    for(int i=1;i<=n;i++) cin>>d[i],mx=max(mx,d[i]);
    for(int i=1;i<=n;i++) {
        int len=ceil(50.0*d[i]/mx);
        putchar('+');
        for(int i=1;i<=len;i++) putchar('-');
        puts("+");
        putchar('|');
        for(int j=1;j<=len;j++) {
            if(j==len && d[i]==mx) putchar('*');
            else putchar(' ');
        }
        printf("|%d\n",d[i]);
        putchar('+');
        for(int i=1;i<=len;i++) putchar('-');
        puts("+");
    }
}

G-Greetings Souvenir

首先启发式合并出每个子树的所有颜色,这样我们点到值连边就有 O ( n 2 ) O(n^2) O(n2)条边,然后
b i t s e t bitset bitset+匈牙利这种 O ( n 3 ) O(n^3) O(n3)的大暴力可以得到 83 83% 83的分数.

正解: 虚树+网络流+二分.
我们考虑对每一个颜色建一颗虚树,那么虚树的一边上 对应原树的每个点 取该颜色都会得到一样的值.
这依然是 O ( n 2 ) O(n^2) O(n2)条边. 我们考虑用倍增优化建图. 即每 2 k 2^k 2k个点压成一个新点.
这样总边数即为 O ( n log ⁡ n ) O(n\log n) O(nlogn).
然后我们二分答案,把值和汇点连边.
如果能流满,那么下次直接用残余网络直接跑.
听说分层图网络流的复杂度为 O ( n m ) O(nm) O(nm),那么这题就是 O ( n 2 log ⁡ n ) O(n^2\log n) O(n2logn)啦~~

#include<bits/stdc++.h>
#define fi first
#define se second
#define lc (x<<1)
#define rc (x<<1|1)
#define gc (p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define IT iterator 
#define vi vector<int>
#define TP template<class o>
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=2e4+10,T=17,size=1<<20,inf=2e9;

char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
    char c=gc; x=0; int f=1;
    while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
    while(isdigit(c)) x=x*10+c-'0',c=gc;
    x*=f;
}
template<class o> void qw(o x) {
    if(x/10) qw(x/10);
    putchar(x%10+'0');
}
template<class o> void pr1(o x) {
    if(x<0)x=-x,putchar('-');
    qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
    if(x<0)x=-x,putchar('-');
    qw(x); putchar('\n');
}

int n,dep[N],fa[N][T],col[N],dfn[N],ID;
struct edge{int y,next; } a[N]; int len,last[N];
void ins(int x,int y) {a[++len]=(edge){y,last[x]}; last[x]=len; }

void dfs(int x) {
    dfn[x]=++ID;
    for(int k=last[x],y;k;k=a[k].next) {
            y=a[k].y;
            for(int i=1;i<T;i++) fa[y][i]=fa[fa[y][i-1]][i-1];
            dep[y]=dep[x]+1; dfs(y);
        }
}

int lca(int x,int y) {
    if(dep[x]<dep[y]) swap(x,y);
    for(int k=dep[x]-dep[y],i=0; k;i++)
        if(k>>i&1) x=fa[x][i],k^=1<<i;
    if(x==y) return x;
    for(int i=T-1;i>=0;i--)
        if(fa[x][i]^fa[y][i]) x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}

namespace D {
    const int N=2e4*T,M=N*5;
    struct E{int y,next,c; } a[M],A[M]; int len=1,last[N],cur[N],LAST[N],LEN;
    void ins(int x,int y,int c) {a[++len]=(E){y,last[x],c}; last[x]=len; }
    void add(int x,int y,int c) {ins(x,y,c); ins(y,x,0); }
    int d[N],q[N],l,r,st,ed,tot;
    bool bfs() {
        for(int i=1;i<=tot;i++) cur[i]=last[i],d[i]=0;
        q[l=r=1]=st; d[st]=1;
        for(int x=st;l<=r;x=q[++l])
            for(int k=last[x],y;k;k=a[k].next) 
                if(a[k].c&&!d[y=a[k].y]) {d[y]=d[x]+1; q[++r]=y; }
        return d[ed];
    }
    int dfs(int x,int f) {
        if(x==ed) return f;
        int s=0,t;
        for(int &k=cur[x],y,z;k;k=a[k].next) {
            y=a[k].y; z=min(f-s,a[k].c);
            if(z&&d[y]==d[x]+1) {
                s+=t=dfs(y,z);
                a[k].c-=t;
                a[k^1].c+=t;
                if(s==f) return f;
            }
        }
        if(!s) d[x]=0;
        return s;
    }
    int dicnic() {int ans=0; while(bfs()) ans+=dfs(st,inf); return ans; }
    void save() {
        LEN=len;
        for(int i=1;i<=tot;i++) LAST[i]=last[i];
        for(int i=1;i<=len;i++) A[i]=a[i];
    }
    void get() {
        len=LEN;
        for(int i=1;i<=tot;i++) last[i]=LAST[i];
        for(int i=1;i<=len;i++) a[i]=A[i];
    }
    // bool vis[N];
    // void debug(int x) {
    //     vis[x]=1;
    //     for(int k=last[x],y;k;k=a[k].next)
    //         if(!vis[y=a[k].y]&&a[k].c) debug(y);
    // }
}

//初始构图
int id[N][T];
void init() {
    for(int i=1;i<=n;i++) id[i][0]=i;//1~n为树上的点
    D::tot=2*n+1; //n+1~2*n+1 为[0,n]的值
    for(int j=1;j<T;j++)
        for(int i=1;i<=n;i++) if(dep[i]>=(1<<j)) {
            id[i][j]=++D::tot;
            D::add(id[i][j-1],id[i][j],1<<(j-1));
            D::add(id[fa[i][j-1]][j-1],id[i][j],1<<(j-1));
        }
    D::st=++D::tot; D::ed=++D::tot;
    for(int i=1;i<=n;i++) D::add(D::st,i,1),D::add(i,n+1,1);//注意每个点的值都可以为0
}

vi C[N];
namespace VT {//虚树上两点之间 对应 原树上的链,c*sz的值相同.
    int sta[N],top;
    void add(int x,int y,int val) {
        val+=n+1;
    
        int p=0,k=dep[x]-dep[y];
        while((1<<(p+1))<=k) p++;
        D::add(id[x][p],val,1<<p);
        for(int i=0;i<p;i++)
            if(k>>i&1) x=fa[x][i];
        D::add(id[x][p],val,1<<p);
    }
    edge a[N]; int len,last[N];
    void ins(int x,int y) {a[++len]=(edge){y,last[x]}; last[x]=len;}
    int dfs(int x,int fa,int c) {
        int sz=(col[x]==c);
        for(int k=last[x];k;k=a[k].next) sz+=dfs(a[k].y,x,c);
        last[x]=0;
        if(1LL*sz*c<=n) add(x,fa,sz*c);
        return sz;
    }
    bool cmp(int x,int y) {return dfn[x]<dfn[y]; }
    void bt(int c) {
        sort(all(C[c]),cmp);
        sta[top=1]=1; len=0;
        for(int x:C[c]) {
            if(x==1) continue;
            int y=lca(x,sta[top]);
            while(top>1&&dep[sta[top-1]]>=dep[y]) ins(sta[top-1],sta[top]),top--;
            if(sta[top]^y) ins(y,sta[top]),sta[top]=y;
            sta[++top]=x; 
        }
        while(top>1) ins(sta[top-1],sta[top]),top--;
        dfs(1,0,c);
    }
}

int main() {
    // freopen("a.in","r",stdin);
    qr(n);
    for(int i=2;i<=n;i++) qr(fa[i][0]),ins(fa[i][0],i);
    dfs(1); for(int i=1;i<=n;i++) qr(col[i]),C[col[i]].pb(i);
    init(); 
    for(int i=1;i<=n;i++) 
        if(SZ(C[i])) VT::bt(i);
    D::save();

    int l=0,r=n,ans=-1,mid,t;
    while(l<=r) {
        mid=(l+r)>>1;
        for(int i=ans+1;i<=mid;i++) D::add(n+1+i,D::ed,1);
        if((t=D::dicnic())==mid-ans) {
            ans=mid; l=mid+1;
            D::save();
        }
        else {
            r=mid-1;
            D::get();
        }
    }
    pr2(ans+1); 
    return 0;
}

H-Interval

容易发现以一个位置 i i i为左端点,总共只有 log ⁡ a [ i ] \log a[i] loga[i]种不同的取值.
我们可以把所有情况找出,然后把同值的情况找出来:
如果存在包含,则删掉大的,保留小的.
然后,为了不重复计算,我们每相邻两个就放一个权为-1的段.
之后就是一个二维偏序问题.
直接动态开点权值树就行啦~~


int n,a[N],m,pos[33];
map<int,int> delta;

struct node *null=NULL,*root[N];
struct node {
    node *ch[2];  int v; 
    #define lc ch[0]
    #define rc ch[1]
    node(int c=0) {lc=rc=null; v=c; }
    void upd(node *x,int l,int r,int pos,int d) {
        v += d; if(l == r) return ;
        int mid=(l+r)/2,c=(pos>mid);
        if(ch[c]==null) ch[c]=new node(x->ch[c]->v);
        ch[c]->upd(x->ch[c],!c?l :mid+1,!c?mid :r,pos,d);
    }
    void add(node *x,int l,int r) {
        if(l==r||x==null) return ;
        int mid=(l+r)/2;
        if(lc==null) lc=x->lc;
        else lc->add(x->lc,l,mid);
        if(rc==null) rc=x->rc;
        else rc->add(x->rc,mid+1,r);
        v=lc->v+rc->v;
    }
    int ask(int l,int r,int pos) {
        if(pos<l) return 0;
        if(r<=pos) return v;
        int mid=(l+r)/2;
        return lc->ask(l,mid,pos)+rc->ask(mid+1,r,pos);
    }
};

struct rec {
    int x,y,z;
    rec(int a=0,int b=0,int c=1) {x=a; y=b; z=c; }
    bool operator <(rec b) const {return x^b.x?x<b.x:y<b.y;}
    bool in(rec b) const {return b.y<=y;}
} sta[N],b[N*60]; int top,cnt;
map<int,vector<rec> > s;

void init() {
    cnt=0;
    for(auto p:s) {
        top=0;
        // printf("\n%d:\n",p.first);
        sort(all(p.se));
        for(auto it:p.se) {
            // pr1(it.x); pr2(it.y);
            while(top&&sta[top].in(it)) top--;
            sta[++top]=it;
        }
        for(int i=1;i<top;i++) b[++cnt]=rec(sta[i].x,sta[i+1].y,-1);
        while(top) b[++cnt]=sta[top--];
    }
}

int main() {
    qr(n); for(int i=1;i<=n;i++) qr(a[i]);
    for(int i=0;i<=30;i++) pos[i]=n+1;
    for(int i=n;i;i--) {
        delta.clear();
        for(int j=0;j<30;j++)
            if(a[i]>>j&1) delta[pos[j]] |= 1<<j;
            else pos[j]=i;
        int x=a[i]; s[x].pb(rec(i,i));
        for(auto p:delta)
            if(p.fi<=n) x^=p.se,s[x].pb(rec(i,p.fi));
    }
    init(); null=new node; null->lc=null->rc=null; root[0]=null;
    sort(b+1,b+cnt+1);
    int c=0;
    for(int i=1,j=1;i<=n;i++) {
        root[i]=new node;
        for( ;j<=cnt&&b[j].x==i;j++) 
            root[i]->upd(root[i-1],1,n,b[j].y,b[j].z),c+=(i==2)*b[j].z*(b[j].y==2);
        root[i]-> add(root[i-1],1,n);
    }
    int ans=0,l,r; qr(m); while(m--) {
        qr(l); qr(r);
        l=(l^ans)%n+1;
        r=(r^ans)%n+1;
        if(l>r) swap(l,r);
        pr2(ans=root[r]->ask(1,n,r)-root[l-1]->ask(1,n,r));
    }
    return 0;
}

I-Hard Math Problem

可以发现 H , E H,E H,E等价,所以我们可以当做两者数量相等.
a n s = x ans=x ans=x,根据相邻格子有4个,我们可以推出等式:
4 ∗ 1 − x 2 = x → x = 2 3 4*\dfrac {1-x}{2}=x\rightarrow x=\dfrac 23 421x=xx=32.
具体的构造方法为:斜行每三行一个周期,前两个周期都是 H H H,最后一个周期 G , E G,E G,E交替.
刑如:
H H G H H G HHGHHG HHGHHG
H E H H E H HEHHEH HEHHEH
G H H G H H GHHGHH GHHGHH
H H E H H G HHEHHG HHEHHG
H G H H E H HGHHEH HGHHEH
E H H G H H EHHGHH EHHGHH
因为无穷大,所以可以看作每个周期长度相等,同样可以得出 2 3 \dfrac 23 32.

#include<cstdio>
int main() {
    puts("0.666667");
}

K-Git Merge

简单DP一下.
f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k],表示 b r a n c h 1   i branch1~i branch1 i行, b r a n c h 2   j branch2~j branch2 j行,最后一个状态为 k k k的最少行数.
k ∈ [ 0 , 4 ) k\in [0,4) k[0,4),分别表示最后无ifdef,只ifdef branch1,只ifdef branch2,都ifdef 了.

然后很恶心的是这题要卡空间…

#include<bits/stdc++.h>
#define fi first
#define se second
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define IT iterator 
#define vi vector<int>
#define TP template<class o>
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=4010,size=1<<20,inf=2e9;
const ll mod=(ll) 1e14+233;

//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
    char c=gc; x=0; int f=1;
    while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
    while(isdigit(c)) x=x*10+c-'0',c=gc;
    x*=f;
}
template<class o> void qw(o x) {
    if(x/10) qw(x/10);
    putchar(x%10+'0');
}
template<class o> void pr1(o x) {
    if(x<0)x=-x,putchar('-');
    qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
    if(x<0)x=-x,putchar('-');
    qw(x); putchar('\n');
}

int n,m;
short f[N][N][4];
char pre[N][N][4];

string a[N],b[N],c,b1="<<<<<<< branch1",b2="=======",ed=">>>>>>> branch2",op1="#ifdef branch1",op2="#ifdef branch2",op3="#else",op4="#endif";
ll va[N],vb[N];

void upd(int i,int j,int k,int I,int J,int K,int d) {
    if(f[i][j][k]>f[I][J][K]+d) {
        f[i][j][k]=f[I][J][K]+d;
        pre[i][j][k]=(i-I)*8+(j-J)*4+K;
    }
}

ll Hash(string &s) {
    ll ans=0;
    for(auto i:s) ans=(ans*2333LL+i)%mod;
    return ans;
}

void put(const string &s) {puts(s.c_str());}

int px,py;//上一个0的位置 
void dfs(int i,int j,int k) {
    if(!i&&!j) {px=py=0; return ;}
    char t=pre[i][j][k];
    dfs(i-t/8,j-(t%8)/4,t%4); t%=4;
    if(!k) {
        if(t==3) {
            put(op1);
            for(int x=px+1;x<i;x++) put(a[x]);
            put(op3);
            for(int y=py+1;y<j;y++) put(b[y]);
            put(op4);
        }
        else if(t==1) {
            put(op1);
            for(int x=px+1;x<i;x++) put(a[x]);
            put(op4);
        }
        else if(t==2) {
            put(op2);
            for(int y=py+1;y<j;y++) put(b[y]);
            put(op4);
        }
        put(a[i]); px=i; py=j;
    }
}

int main() {
    int x=1,y=1;
    while(getline(cin,c)) {
        if(c==b1) x=1,y=0;
        else if(c==b2) x=0,y=1;
        else if(c==ed) x=y=1;
        else {
            int val=Hash(c);
            if(x) a[++n]=c,va[n]=val;
            if(y) b[++m]=c,vb[m]=val;
        }
    }
    va[++n]=vb[++m]=-1;
    memset(f,63,sizeof f); f[0][0][0]=0;
    upd(1,0,1,0,0,0,3); for(int i=2;i<=n;i++) upd(i,0,1,i-1,0,1,1);
    upd(0,1,2,0,0,0,3); for(int j=2;j<=m;j++) upd(0,j,2,0,j-1,2,1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) {
            // f[i][j][1]=min(f[i-1][j][1]+1,f[i-1][j][0]+3);
            upd(i,j,1,i-1,j,1,1); upd(i,j,1,i-1,j,0,3);
            // f[i][j][2]=min(f[i][j-1][2]+1,f[i][j-1][0]+3);
            upd(i,j,2,i,j-1,2,1); upd(i,j,2,i,j-1,0,3);
            // f[i][j][3]=min({f[i-1][j-1][3],f[i-1][j-1][1]+1,f[i-1][j-1][2]+1,f[i-1][j-1][0]+3})+2;
            upd(i,j,3,i-1,j-1,3,2);
            upd(i,j,3,i-1,j-1,1,3);
            upd(i,j,3,i-1,j-1,2,3);
            upd(i,j,3,i-1,j-1,0,5);
            if(va[i]==vb[j]) {
                for(int k=0;k<4;k++)
                    upd(i,j,0,i-1,j-1,k,1);
            }
        }
    
    dfs(n,m,0); return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Infinite_Jerry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值