zoukankan      html  css  js  c++  java
  • AtCoder Regular Contest 097

    AtCoder Regular Contest 097


    C - K-th Substring

    题意:求一个长度小于等于5000的字符串的第K小子串,相同子串算一个。

    K<=5。

    分析:这不是弦论那道题吗。。

    观察到K<=5,我们把所有长度小于等于5的子串拿出来去重再排个序即可。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 5050
    int K,n;
    struct A {
    	char s[10];
    	bool operator < (const A &x) const {
    		return strcmp(s,x.s)<0;
    	}
    	bool operator == (const A &x) const {
    		return strcmp(s,x.s)==0;
    	}
    }a[N<<3];
    char s[N];
    int main() {
    	int cnt=0;
    	scanf("%s%d",s,&K);
    	int i,j,k;n=strlen(s);
    	for(i=0;i<n;i++) {
    		for(j=1;j<=5&&i+j-1<n;j++) {
    			++cnt;
    			for(k=i;k<=i+j-1;k++) a[cnt].s[k-i]=s[k];
    		}
    	}
    	sort(a+1,a+cnt+1);
    	cnt=unique(a+1,a+cnt+1)-a-1;
    	printf("%s
    ",a[K].s);
    }
    

    D - Equals

    题意:给出一个n的排列,m条信息,每个信息(x,y)表示可以交换位置为x和y的两个数。

    可以进行若干次操作,求操作后最多有多少ai=i。

    分析:把信息当成边,可以发现一个连通块里的点可以乱窜,直接判断每个位置和对应的值在不在一个连通块内即可。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 100050
    int fa[N],a[N],n,m,ans;
    int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
    int main() {
    	int i;
    	scanf("%d%d",&n,&m);
    	int x,y;
    	for(i=1;i<=n;i++) scanf("%d",&a[i]),fa[i]=i;
    	for(i=1;i<=m;i++) {
    		scanf("%d%d",&x,&y);
    		int dx=find(x),dy=find(y);
    		if(dx!=dy) fa[dx]=dy;
    	}
    	for(i=1;i<=n;i++) if(find(a[i])==find(i)) ans++;
    	printf("%d
    ",ans);
    }
    

    E - Sorted and Sorted

    题意:有n个白球和n个黑球,编号为1到n。现在让你每次交换相邻的两个球,使得最后黑球编号递增,白球编号递增。

    分析:贪心的想每次肯定从编号小往前移动,但每次可以移动黑球也可以移动白球。

    于是设f[i][j]表示白球已经放了前i个,黑球已经放了前j个的最小移动次数。

    转移f[i][j]+编号为i+1的白球前面有多少编号大于i+1的白球,有多少编号大于j的黑球->f[i+1][j]

    f[i][j]+编号为j+1的黑球前面有多少编号大于i的白球,有多少编号大于j+1的黑球->f[i][j+1]

    O(n^2)预处理出来第i个球前面都多少大于j的白/黑球即可。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 2050
    int f[N][N],opt[N<<1],a[N<<1],cw[N<<1][N],cb[N<<1][N],pos[2][N],n;
    char str[10];
    int main() {
    	scanf("%d",&n);
    	int i,j;
    	for(i=1;i<=(n<<1);i++) {
    		scanf("%s%d",str,&a[i]);
    		opt[i]=(str[0]=='B'); pos[opt[i]][a[i]]=i;
    	}
    	for(i=1;i<=(n<<1);i++) {
    		for(j=0;j<=n;j++) {
    			cw[i][j]=cw[i-1][j];
    			cb[i][j]=cb[i-1][j];
    			if(a[i-1]>j) opt[i-1]?cb[i][j]++:cw[i][j]++;
    		}
    	}
    	memset(f,0x3f,sizeof(f));
    	f[0][0]=0;
    	for(i=0;i<=n;i++) {
    		for(j=0;j<=n;j++) {
    			int u=pos[0][i+1],v=pos[1][j+1];
    			f[i+1][j]=min(f[i+1][j],f[i][j]+cw[u][i+1]+cb[u][j]);
    			f[i][j+1]=min(f[i][j+1],f[i][j]+cw[v][i]+cb[v][j+1]);
    		}
    	}
    	printf("%d
    ",f[n][n]);
    }
    

    F - Monochrome Cat

    题意:有一棵树,每个结点是黑色或白色,你可以选择一个起点开始走,每秒有两种选择。

    1.走向一个相邻的结点,并翻转该结点的颜色。

    2.在原地翻转结点的颜色。

    分析:任选一个白色结点当做根。显然对于全黑色的子树不会被遍历到,于是删掉这样的。

    树上所有叶子结点都变成白色的了。

    考虑起点和终点相同的情况。首先每条边要走两次,并且对于度数+颜色%2==0的点还要花费1时间来翻转成黑色。

    那么考虑起点和终点不一样的情况,还是起点、终点都是叶子。

    走的路径相当于少了一条链+终点,考虑链上原来的黑点没有减少答案,原来的白点减少了2(遍历一次翻转一次)。相当于每个点赋一个点权。

    现在要求一条起点叶子终点叶子的路径,路径上点权和最大。

    设f[i]表示i到叶子的最大和,g[i]表示i到叶子的父亲的最大和(叶子是终点)。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 100050
    char str[N];
    int head[N],to[N<<1],nxt[N<<1],a[N],c[N],cnt,siz[N],f[N],g[N],si[N],d[N],n,ans;
    inline void add(int u,int v) {
    	to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
    }
    void dfs(int x,int y) {
    	int i;siz[x]=1; si[x]=c[x];
    	for(i=head[x];i;i=nxt[i]) {
    		if(to[i]!=y) {
    			dfs(to[i],x); siz[x]+=siz[to[i]]; si[x]+=si[to[i]];
    			if(si[to[i]]!=siz[to[i]]) d[to[i]]++,d[x]++;
    		}
    	}
    }
    void dfs2(int x,int y) {
    	int i;
    	int mx1=0,mx2=0;
    	if(d[x]==1&&y) {f[x]=a[x],g[x]=-1<<30; return ;}
    	for(i=head[x];i;i=nxt[i]) {
    		if(to[i]!=y&&siz[to[i]]!=si[to[i]]) {
    			dfs2(to[i],x);
    			ans=max(ans,f[to[i]]+mx2+a[x]);
    			ans=max(ans,g[to[i]]+mx1+a[x]);
    			mx1=max(mx1,f[to[i]]);
    			mx2=max(mx2,g[to[i]]);
    		}
    	}
    	f[x]=mx1+a[x]; g[x]=mx2+a[x];
    }
    int main() {
    	scanf("%d",&n);
    	int i,x,y;
    	for(i=1;i<n;i++) {
    		scanf("%d%d",&x,&y); add(x,y); add(y,x);
    	}
    	scanf("%s",str+1);
    	int rt=0;
    	for(i=1;i<=n;i++) {
    		c[i]=(str[i]=='B');
    		if(!c[i]) rt=i;
    	}
    	if(rt) dfs(rt,0);
    	else {
    		puts("0"); return 0;
    	}
    	int sum=0;
    	for(i=1;i<=n;i++) {
    		if(siz[i]==si[i]) continue;
    		sum+=d[i];
    		if((d[i]+c[i])%2==0) sum++,a[i]=2;
    	}
    	dfs2(rt,0);
    	printf("%d
    ",sum-ans);
    }
    
  • 相关阅读:
    linux 回收站 路径
    Linux 让进程在后台可靠运行的几种方法
    用marquee和div+js实现首尾相连循环滚动效果
    轻型数据库SQLite结合PHP的开发
    linux系统权限修复——学生误操作!
    2009级 毕业设计 题目
    linux下硬盘uuid查看及修改设置
    创建网站地图
    用上下左右箭头键在textbox中的光标跳转
    SHELL中时间的比较
  • 原文地址:https://www.cnblogs.com/suika/p/9252272.html
Copyright © 2011-2022 走看看