• 【AtCoder】 ARC 097


    C-K-th Substring

    题意:找出已知串中第(k)大的子串,子串相同的不算

    (k)好小啊,要怎么做啊

    不是【Tjoi2015】弦论

    算了,直接SAM吧

    #include<bits/stdc++.h>
    #define ll long long
    #define dbg1(x) cerr<<#x<<"="<<(x)<<" "
    #define dbg2(x) cerr<<#x<<"="<<(x)<<"
    "
    #define dbg3(x) cerr<<#x<<"
    "
    using namespace std;
    #define reg register
    const int MN=1e4+4;
    char s[5005];int K;
    int c[MN][26],step[MN],val[MN],fa[MN],siz[MN],v[MN],rk[MN];
    int last,cnt,n;
    inline void init()
    {
        last=cnt=1;memset(c,0,sizeof c);
        reg int i;
        for(i=1;i<n<<1;++i) val[i]=step[i]=fa[i]=0;
    }
    void Insert(int x)
    {
        int p=last,np=++cnt;step[np]=step[p]+1;val[np]=1;
        for(;p&&!c[p][x];p=fa[p]) c[p][x]=np;
        if(!p) fa[np]=1;
        else 
        {
            int q=c[p][x];
            if(step[q]==step[p]+1) fa[np]=q;
            else 
            {
                int nq=++cnt;step[nq]=step[p]+1;
                memcpy(c[nq],c[q],sizeof c[q]);
                fa[nq]=fa[q];fa[np]=fa[q]=nq;
                for(;c[p][x]==q;p=fa[p]) c[p][x]=nq;
            }    
        }
        last=np;
    }
    inline void work()
    {
        reg int i,j;
        for(i=1;i<=cnt;++i) ++v[step[i]];
        for(i=1;i<=n;++i) v[i]+=v[i-1];
        for(i=1;i<=cnt;++i) rk[v[step[i]]--]=i;
    	for(i=2;i<=cnt;++i) val[i]=siz[i]=1;
        val[1]=siz[1]=0;
        for(i=cnt;i;--i)for(j=0;j<26;++j)
    		if(c[rk[i]][j])siz[rk[i]]+=siz[c[rk[i]][j]];
    }
    char ans[MN];int len;
    inline void dfs(int x,int k)
    {
        if(k<=val[x]) return;k-=val[x];
        reg int i;
        for(i=0;i<26;++i)
            if(k>siz[c[x][i]]) k-=siz[c[x][i]];
            else {ans[len++]=i+'a',dfs(c[x][i],k);break;}
    }
    int main()
    {
        reg int i,k;
        scanf("%s%d",s+1,&k);n=strlen(s+1);
        init();
        for(i=1;i<=n;++i) Insert(s[i]-'a');
        work();
        dfs(1,k),printf("%s",ans);
        return 0;
    }
    



    D-Equals

    题意:一个排列,一些位置对可任意交换,最大化(p_i=i)(i)的数量

    并查集把每个可以互相通达的部分找出来即可

    #include<bits/stdc++.h>
    #define ll long long
    #define dbg1(x) cerr<<#x<<"="<<(x)<<" "
    #define dbg2(x) cerr<<#x<<"="<<(x)<<"
    "
    #define dbg3(x) cerr<<#x<<"
    "
    using namespace std;
    #define reg register
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return x*f;
    }
    const int MN=1e5+5;
    int N,M,p[MN];
    int fa[MN];
    int getf(int x){return x==fa[x]?x:fa[x]=getf(fa[x]);}
    int main()
    {
    	N=read(),M=read();
    	reg int i,x,y;
    	for(i=1;i<=N;++i) p[read()]=i,fa[i]=i;
    	for(i=1;i<=M;++i)
    	{
    		x=read(),y=read();
    		if(getf(x)^getf(y)) fa[getf(x)]=fa[getf(y)];
    	}
    	int ans=0;
    	for(i=1;i<=N;++i) ans+=(getf(i)==getf(p[i]));
    	return 0*printf("%d
    ",ans);
    }
    



    E-Sorted and Sorted

    题意(N)个黑球(N)个白球,交换相邻的球使最终排列满足黑白两色均升序,最小化交换次数

    dp,相当于对球的序列进行重新标号,最小化逆序对数

    可以设(f_{i,j})表示前(i)个白球和前(j)个黑球重标号后的最小逆序对数,转移时枚举最后一个球的颜色

    #include<bits/stdc++.h>
    #define ll long long
    #define dbg1(x) cerr<<#x<<"="<<(x)<<" "
    #define dbg2(x) cerr<<#x<<"="<<(x)<<"
    "
    #define dbg3(x) cerr<<#x<<"
    "
    using namespace std;
    #define reg register
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    const int MN=2005;
    int N,f[MN][MN],g[2][MN][MN],T[2][MN];
    void C(int x,int y){for(;x<=N;x+=(x&(-x)))T[y][x]++;}
    int G(int x,int y){int r=0;for(;x;x-=(x&(-x)))r+=T[y][x];return r;}
    int main()
    {
    	N=read();
    	reg int i,j;char c;
    	for(i=1;i<=N*2;++i)
    	{
    		scanf("%c",&c);
    		if(c=='W')
    		{
    			int x=read();C(x,0);
    			for(j=0;j<=N;++j) g[0][x][j]=x+j-G(x,0)-G(j,1);
    		}
    		else
    		{
    			int x=read();C(x,1);
    			for(j=0;j<=N;++j) g[1][j][x]=x+j-G(x,1)-G(j,0);
    		}
    	}
    	for(i=1;i<=N;++i) f[i][0]=f[i-1][0]+g[0][i][0];
    	for(i=1;i<=N;++i) f[0][i]=f[0][i-1]+g[1][0][i];
    	for(i=1;i<=N;++i)for(j=1;j<=N;++j)
    		f[i][j]=min(f[i-1][j]+g[0][i][j],f[i][j-1]+g[1][i][j]);
    	return 0*printf("%d
    ",f[N][N]);
    }
    



    F-Monochrome Cat

    题意:一棵黑白两色的树,树上任意选择一个点开始移动,每次可以耗费一单位时间来改变当前点的颜色或是耗费一单位时间来进行一次移动,使得所有都是黑色的最小时间

    把黑色部分给去掉,使得所有度数为一的点的颜色都是白色,这时,路径必然经过每个点,可以发现每条边最多经过两次,先假设每条边都经过了两次,而经过一次的边必然为一条连续的路径,简单树d可以完成。

    #include<bits/stdc++.h>
    #define ll long long
    #define dbg1(x) cerr<<#x<<"="<<(x)<<" "
    #define dbg2(x) cerr<<#x<<"="<<(x)<<"
    "
    #define dbg3(x) cerr<<#x<<"
    "
    using namespace std;
    #define reg register
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    const int MN=1e5+5,inf=0x7fffffff;
    int N;
    bool c[MN];
    struct edge{int to,nex;}e[MN<<1];
    int en,hr[MN];
    void ins(int x,int y)
    {
    	e[++en]=(edge){y,hr[x]};hr[x]=en;
    	e[++en]=(edge){x,hr[y]};hr[y]=en;
    }
    int sw[MN],fa[MN],rt,sW;
    void dfs1(int x,int f=0)
    {
    	reg int i;sw[x]=c[x];fa[x]=f;
    	for(i=hr[x];i;i=e[i].nex)if(e[i].to^f)dfs1(e[i].to,x),sw[x]+=sw[e[i].to];
    	if(sw[x]==sW&&!rt)rt=x;
    }
    int ans,son[MN],deg[MN];
    void dfs2(int x)
    {
    	if(!sw[x])return;++son[fa[x]];if(x!=rt)ans+=2;
    	for(int i=hr[x];i;i=e[i].nex)if(e[i].to^fa[x])dfs2(e[i].to);
    	ans+=(deg[x]=son[x]+c[x]+(x!=rt))&1;deg[x]=deg[x]&1?1:-1;
    }
    int dp[MN][2];
    #define fi first
    #define se second
    void dfs3(int x)
    {
    	reg int i;
    	if(!sw[x])return;pair<int,int> p;p.fi=p.se=0;
    	for(i=hr[x];i;i=e[i].nex)if(e[i].to!=fa[x]&&sw[e[i].to])
    	{
    		dfs3(e[i].to);
    		dp[x][0]=max(dp[x][0],dp[e[i].to][0]);
    		dp[x][1]=max(dp[x][1],deg[x]+1+dp[e[i].to][1]);
    	}
    	if(son[x]>=2)
    	{
    		for(i=hr[x];i;i=e[i].nex)if(e[i].to!=fa[x]&&sw[e[i].to])
    		{
    			int v=dp[e[i].to][1];
    			if(v>p.fi)p.se=p.fi,p.fi=v;
    			else if(v>p.se)p.se=v;
    		}
    		dp[x][0]=max(dp[x][0],deg[x]+1+p.fi+p.se);
    	}
    	dp[x][0]=max(dp[x][0],dp[x][1]);
    }
    char s[MN];
    int main()
    {
    	N=read();reg int i,x;
    	for(i=1;i<N;++i) x=read(),ins(x,read());
    	scanf("%s",s+1);
    	for(i=1;i<=N;++i) c[i]=s[i]=='W',sW+=c[i];
    	dfs1(1);dfs2(rt);dfs3(rt);
    	return 0*printf("%d
    ",ans-dp[rt][0]);
    }
    


    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    20165334 第十三周选做
    20165334 实验五 网络编程与安全
    ### 20165334 —— 第十二周MySort(选作)
    2018-2019-1 20165227 20165228 20165237 实验一 开发环境的熟悉
    2018-2019-1 20165228 《信息安全系统设计基础》第四周学习总结
    2018-2019-1 20165228《信息安全系统设计基础》第三周课上测试
    2018-2019-1 20165228 《信息安全系统设计基础》第三周学习总结
    2018-2019-1 20165228 《信息安全系统设计基础》缓冲区溢出漏洞实验报告
    2018-2019-1 20165228 《信息安全系统设计基础》第二周学习总结
    2018-2019-1 20165228 苏祚堃《信息安全系统设计基础》第一周学习总结
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/11478843.html
Copyright © 2020-2023  润新知