NOI2015题解

D1T1:
先用并查集把相等关系并起来再看有没有同一个联通块的不等关系

D1T2:
树剖

D1T3:
大概思想就是根据一个数 > x 的因子只有1个,对 < n 的质因子状压, > n 的暴力枚举
之前写过题解

D2T1:
K = 2 时可以直接用huffman树做
K 2 时,若 n 不满足 n 1 0 ( mod K 1 ) ,这棵树就不是满的k叉树,直接像huffman树那样做会错因为这样做树根的孩子不足k个,而把某些子树里的点提上来显然更优,于是我们补若干个权值为 0 的虚点直到这棵树满
要求最长的串最短的限制只要比较时里把长度设为第二关键字就行了

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

inline void up(int &a,const int &b){if(a<b)a=b;}
const int maxn = 310000;

int n,K;
int l[maxn],cnt;
ll a[maxn],siz[maxn];
struct node
{
    ll x;
    int len,i;
    friend inline bool operator <(const node x,const node y)
    {
        return x.x==y.x?x.len>y.len:x.x>y.x;
    }
};
priority_queue<node>q;

int t[maxn],tp;
ll ans1; int ans2;
void Solve()
{
    for(int i=1;i<=n;i++) q.push((node){siz[i]=a[i],l[i]=0,i});
    cnt=n;

    while(q.size()>1)
    {
        tp=0;
        for(int j=1;j<=K&&!q.empty();j++)
        {
            const node now=q.top(); q.pop();
            t[++tp]=now.i;
        }
        int mx=0;
        for(int j=1;j<=tp;j++) up(mx,l[t[j]]);

        ++cnt,l[cnt]=mx+1;
        for(int j=1;j<=tp;j++) siz[cnt]+=siz[t[j]];
        ans1+=siz[cnt];

        q.push((node){siz[cnt],l[cnt],cnt});
    }
    ans2=l[cnt];
}

int main()
{
    //freopen("ex_epic3.in","r",stdin);
    //freopen("tmp.out","w",stdout);

    scanf("%d%d",&n,&K);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    while(K!=2&&n%(K-1)!=1) a[++n]=0;

    Solve();
    printf("%lld\n%d\n",ans1,ans2);

    return 0;
}

D2T2:
注意权值有负数所以要维护最小值

后缀数组做法:把height值塞到vector里,从大到小处理答案,处理到 x 时,将 h e i g h t = x 的拿出来,用并查集把他们并在一起,同一联通块里的一定两两的height值都 >= x ,维护每个联通块里权值最大最小值,合并的时候更新当前答案

SAM做法:把后缀树建出来好像可以直接乱搞

code(后缀数组):

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define pb push_back
#define SZ(x) (int)x.size()
using namespace std;

inline void read(int &x)
{
    char c; while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
inline void down(int &a,const int &b){if(a>b)a=b;}
inline void up(int &a,const int &b){if(a<b)a=b;}
const int maxn = 610000;

int n;
int a[maxn];
int str[maxn];
int sa[maxn],rank[maxn],fir[maxn],sec[maxn];
int t[maxn];
void sort_(int str[],int re[],int rk[],int n,int m)
{
    for(int i=0;i<=m;i++) t[i]=0;
    for(int i=1;i<=n;i++) t[str[rk[i]]]++;
    for(int i=1;i<=m;i++) t[i]+=t[i-1];
    for(int i=n;i>=1;i--) re[t[str[rk[i]]]--]=rk[i];
}
void get_SA()
{
    for(int i=1;i<=n;i++) rank[i]=i;
    sort_(str,sa,rank,n,30);
    rank[sa[1]]=1;
    for(int i=2;i<=n;i++) rank[sa[i]]=rank[sa[i-1]]+(str[sa[i]]!=str[sa[i-1]]);
    int t=1;
    while(rank[sa[n]]!=n)
    {
        for(int i=1;i<=n;i++)
        {
            sa[i]=i;
            fir[i]=rank[i],sec[i]=i+t>n?0:rank[i+t];
        }
        sort_(sec,rank,sa,n,n);
        sort_(fir,sa,rank,n,n);
        rank[sa[1]]=1;
        for(int i=2;i<=n;i++) rank[sa[i]]=rank[sa[i-1]]+(fir[sa[i]]!=fir[sa[i-1]]||sec[sa[i]]!=sec[sa[i-1]]);
        t<<=1;
    }
}
int height[maxn];
void get_Height()
{
    height[1]=0; int k=0;
    for(int i=1;i<=n;i++)
    {
        if(k) k--;
        if(rank[i]==1)continue;
        while(str[i+k]==str[sa[rank[i]-1]+k]) k++;
        height[rank[i]]=k;
    }
}

vector<int>V[maxn];
int fa[maxn],mx[maxn],mn[maxn],siz[maxn];
int findfa(const int x){return fa[x]==x?x:fa[x]=findfa(fa[x]);}


ll ans[maxn],ans2[maxn];
char S[maxn];

int main()
{
    //freopen("ex_savour2.in","r",stdin);
    //freopen("tmp.out","w",stdout);

    read(n);
    scanf("%s",S);
    for(int i=1;i<=n;i++) str[i]=S[i-1]-'a'+1;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);

    get_SA();
    get_Height();

    for(int i=2;i<=n;i++) V[height[i]].pb(i);
    for(int i=1;i<=n;i++) fa[i]=i,mx[i]=mn[i]=a[sa[i]],siz[i]=1;

    ans2[n]=LLONG_MIN;
    for(int i=n-1;i>=0;i--)
    {
        ans[i]=ans[i+1],ans2[i]=ans2[i+1];
        for(int j=0;j<SZ(V[i]);j++)
        {
            int x=V[i][j];
            int f1=findfa(x-1),f2=findfa(x);

            ans[i]+=(ll)siz[f1]*siz[f2];
            siz[f1]+=siz[f2];
            ans2[i]=max(ans2[i],(ll)mx[f1]*mx[f2]);
            ans2[i]=max(ans2[i],(ll)mn[f1]*mn[f2]);
            up(mx[f1],mx[f2]);
            down(mn[f1],mn[f2]);
            fa[f2]=f1;
        }
    }

    for(int i=0;i<n;i++) printf("%lld %lld\n",ans[i],ans2[i]==LLONG_MIN?0:ans2[i]);

    return 0;
}

D2T3
写了好久
然后调了好久
然后发现看错题了….
无限膜拜考场上切了这题的神犇们….

这题分三部分
第一部分是找最长路,按照 y 分层后不同层之间是DAG,按照 y 从小到大做个dp,令 t f [ i ] 表示从下面的层直接走到 i 的最长路, f [ i ] 表示走到 i 的最长路,不同层直接转移,同一层左右各扫一遍用单调性优化一下转移
输出方案就记录一下每个状态是从哪个状态转移过来就好了

第二部分是判断哪些边可能在最长路中
上面那个dp再倒着做一边就能判了

第三部分是用可能在最长路的边建出图后,求最少用多少条链可以覆盖图中所有边,允许重复覆盖
相当于每条边下界1上界inf,跑最小可行流
建超级源ss,超级汇tt,对于一条边(u,v,1,inf),连(ss,v,1),(u,tt,1),(u,v,inf)
然后先不连(t,s,inf),跑一遍ss-tt最大流,这一次的作用相当与尽量把流量导在其他边上面减少s->t的流量,设第一次流量为 w 1
再连上(t,s,inf),跑一遍ss-tt最大流,这次的流量 w 2 就是最小可行流(如果合法),因为这次的流量都是一定要经过这条边的流量

因为 w 1 + w 2 = s s ,这题又保证了有合法解,我们可以只跑第一次,用总流量- w 1 算答案

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define pb push_back
#define mp make_pair
#define SZ(x) (int)x.size()
#define inf 1e9
using namespace std;

inline void up(int &a,const int &b){if(a<b)a=b;}
inline void down(int &a,const int &b){if(a>b)a=b;}
const int maxn = 210000;
const int maxm = maxn*12;

int n;
map<int,int>a,b,c,d; // x,y,x+y,x-y
int an,bn,cn,dn;
struct data
{
    int x,i;
    friend inline bool operator <(const data x,const data y){return x.x<y.x;}
}yi[maxn];
vector<data>va[maxn],vb[maxn],vc[maxn],vd[maxn];
struct point
{
    int x,y;
    int ia,ib,ic,id;
    int ai,bi,ci,di;
}p[maxn];
vector<int>V[maxn],Vi[maxn];
void ins(int x,int y){ V[x].pb(y),Vi[y].pb(x); }
void build()
{
    for(int i=0,tc,j;i<=n;i++)
    {
        tc=p[i].x; if(a.count(tc)==0) a[tc]=++an;
        p[i].ia=j=a[tc]; va[j].pb((data){p[i].y,i});

        tc=p[i].y; if(b.count(tc)==0) b[tc]=++bn;
        p[i].ib=j=b[tc]; vb[j].pb((data){p[i].x,i});

        tc=p[i].x+p[i].y; if(c.count(tc)==0) c[tc]=++cn;
        p[i].ic=j=c[tc]; vc[j].pb((data){p[i].x,i});

        tc=p[i].x-p[i].y; if(d.count(tc)==0) d[tc]=++dn;
        p[i].id=j=d[tc]; vd[j].pb((data){p[i].x,i});
    }

    for(int i=1;i<=an;i++) sort(va[i].begin(),va[i].end());
    for(int i=1;i<=bn;i++) sort(vb[i].begin(),vb[i].end());
    for(int i=1;i<=cn;i++) sort(vc[i].begin(),vc[i].end());
    for(int i=1;i<=dn;i++) sort(vd[i].begin(),vd[i].end());

    for(int i=1;i<=an;i++) for(int j=0;j<SZ(va[i]);j++) p[va[i][j].i].ai=j;
    for(int i=1;i<=bn;i++) for(int j=0;j<SZ(vb[i]);j++) p[vb[i][j].i].bi=j;
    for(int i=1;i<=cn;i++) for(int j=0;j<SZ(vc[i]);j++) p[vc[i][j].i].ci=j;
    for(int i=1;i<=dn;i++) for(int j=0;j<SZ(vd[i]);j++) p[vd[i][j].i].di=j;

    for(int i=0,ii;i<=n;i++)
    {
        ii=p[i].ia; if(p[i].ai+1<SZ(va[ii])) ins(i,va[ii][p[i].ai+1].i);
        ii=p[i].ic; if(p[i].ci) ins(i,vc[ii][p[i].ci-1].i);
        ii=p[i].id; if(p[i].di+1<SZ(vd[ii])) ins(i,vd[ii][p[i].di+1].i);
    }
}
int tf[maxn],f[maxn],pf[maxn],tg[maxn],g[maxn],mxlen;
void ANS1(int x)
{
    mxlen=f[x];
    printf("%d\n",mxlen-1);

    int t[maxn],tp; t[tp=0]=-1;
    while(x)
    {
        if(x<=n) t[++tp]=x;
        else if(x-n!=t[tp]) t[++tp]=x-n;
        if(!x)break;
        if(x<=n)
        {
            int y=pf[x]-n;
            if(p[y].bi<p[x].bi)
            {
                int i=p[y].bi,j=p[x].bi,now=p[x].ib;
                for(int k=j-1;k>i;k--) t[++tp]=vb[now][k].i;
                for(int k=0;k<i;k++) t[++tp]=vb[now][k].i;
            }
            else if(p[y].bi>p[x].bi)
            {
                int i=p[x].bi,j=p[y].bi,now=p[x].ib;
                for(int k=i+1;k<j;k++) t[++tp]=vb[now][k].i;
                for(int k=SZ(vb[now])-1;k>j;k--) t[++tp]=vb[now][k].i;
            }
        }
        x=pf[x];
    }
    for(int i=tp;i>=1;i--) printf("%d%c",t[i],i==1?'\n':' ');
}
void DP()
{
    for(int i=1;i<=bn;i++) yi[i]=(data){p[vb[i][0].i].y,i};
    sort(yi+1,yi+bn+1);

    for(int i=0;i<=n;i++) tf[i]=f[i]=-n*2;
    tf[0]=1;
    for(int ti=1;ti<=bn;ti++)
    {
        const int now=yi[ti].i;

        int mxi=0;
        for(int j=0;j<SZ(vb[now]);j++)
        {
            int i=vb[now][j].i;
            f[i]=tf[i],pf[i]=n+i;
            if(mxi&&tf[mxi]+j>f[i]) f[i]=tf[mxi]+j,pf[i]=n+mxi;
            if(!mxi||tf[mxi]<tf[i]) mxi=i;
        }
        mxi=0;
        for(int j=SZ(vb[now])-1;j>=0;j--)
        {
            int i=vb[now][j].i;
            if(mxi&&tf[mxi]+SZ(vb[now])-1-j>f[i]) f[i]=tf[mxi]+SZ(vb[now])-1-j,pf[i]=n+mxi;
            if(!mxi||tf[mxi]<tf[i]) mxi=i;
        }

        for(int j=0;j<SZ(vb[now]);j++)
        {
            int x=vb[now][j].i;
            for(int i=0;i<SZ(V[x]);i++)
            {
                int y=V[x][i];
                if(f[x]+1>tf[y]) tf[y]=f[x]+1,pf[n+y]=x;
            }
        }
    }

    int ansi=0; for(int i=0;i<=n;i++) if(f[i]>f[ansi]) ansi=i;
    ANS1(ansi);


    for(int i=0;i<=n;i++) tg[i]=1,g[i]=-n*2;
    for(int ti=bn;ti>=1;ti--)
    {
        const int now=yi[ti].i;

        int mxi=0;
        for(int j=0;j<SZ(vb[now]);j++)
        {
            int i=vb[now][j].i;
            g[i]=tg[i];
            if(mxi) up(g[i],tg[mxi]+SZ(vb[now])-1-p[mxi].bi);
            if(!mxi||tg[mxi]-p[mxi].bi<tg[i]-p[i].bi) mxi=i;
        }
        mxi=0;
        for(int j=SZ(vb[now])-1;j>=0;j--)
        {
            int i=vb[now][j].i;
            if(mxi) up(g[i],tg[mxi]+p[mxi].bi);
            if(!mxi||tg[mxi]+p[mxi].bi<tg[i]+p[i].bi) mxi=i;
        }

        for(int j=0;j<SZ(vb[now]);j++)
        {
            int x=vb[now][j].i;
            for(int i=0;i<SZ(Vi[x]);i++)
            {
                int y=Vi[x][i];
                up(tg[y],g[x]+1);
            }
        }
    }
}

namespace Graph
{
    int s,t,ss,tt;
    struct edge{int y,c,nex;}a[maxm]; int len,fir[maxn];
    inline void ins(const int x,const int y,const int c)
    {
        a[++len]=(edge){y,c,fir[x]};fir[x]=len;
        a[++len]=(edge){x,0,fir[y]};fir[y]=len;
    }
    int d[maxn],fullflow;
    void init()
    {
        s=n+1,t=s+1,ss=t+1,tt=ss+1; len=1;
        memset(fir,0,sizeof fir);

        for(int x=0;x<=n;x++)
            ins(s,x,inf),ins(x,t,inf);
        for(int x=0;x<=n;x++) for(int i=0;i<SZ(V[x]);i++)
        {
            int y=V[x][i];
            if(f[x]+g[y]==mxlen)
            {
                ins(x,y,inf);
                d[x]++,d[y]--;
            }
        }
        for(int x=0;x<=n;x++) if(d[x])
        {
            if(d[x]>0) ins(x,tt,d[x]);
            else ins(ss,x,-d[x]),fullflow-=d[x];
        }
    }
    int h[maxn],st,ed,ph[maxn];
    queue<int>q;
    bool bfs()
    {
        for(int i=0;i<=tt;i++) h[i]=0;
        h[st]=1; q.push(st);
        while(!q.empty())
        {
            const int x=q.front(); q.pop();
            for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(a[k].c&&!h[y])
                h[y]=h[x]+1,ph[y]=x,q.push(y);
        }
        return h[ed]>0;
    }
    int dfs(const int x,const int flow)
    {
        if(x==ed) return flow;
        int delta=0;
        for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y)
        {
            if(a[k].c&&h[y]==h[x]+1)
            {
                int minc=dfs(y,min(a[k].c,flow-delta));
                a[k].c-=minc,a[k^1].c+=minc;
                delta+=minc;
            }
            if(delta==flow) return delta;
        }
        if(!delta) h[x]=0;
        return delta;
    }
    int Flow()
    {
        int re=0;
        while(bfs()) re+=dfs(st,inf);
        return re;
    }
    int Solve()
    {
        st=ss,ed=tt;
        return fullflow-Flow();
    }
}

int main()
{
    scanf("%d",&n);
    p[0].x=p[0].y=0;
    for(int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y);

    build();
    DP();

    Graph::init();
    printf("%d\n",Graph::Solve());

    return 0;
}

猜你喜欢

转载自blog.csdn.net/l_0_forever_lf/article/details/80783644