Codeforces Round #468 Div1 A~D解题报告

D题好假E题更假

A.Peculiar apple-tree

题意:一个树上每个节点有一个苹果,每秒下落(既到它的父亲),两个苹果到同一节点瞬间消失,若奇数个剩一个


显然是对于所有深度相同的一起考虑

深度为x的节点数量奇数贡献1,偶数贡献0

#include
#include
#include
#include
#include
#include
#include
#include
#define For(i,j,k)	for(int i=j;i<=k;++i)
#define Dow(i,j,k)	for(int i=k;i>=j;--i)
#define ll long long
#define inf 1e9
using namespace std;
inline int read()
{
	int t=0,f=1;char c=getchar();
	while(!isdigit(c))	{if(c=='-')	f=-1;c=getchar();}
	while(isdigit(c))	t=t*10+c-'0',c=getchar();
	return t*f;
}
inline void write(int x){if(x>=10)	write(x/10);putchar(x%10+'0');}
inline void writeln(int x){write(x);puts("");}
inline void write_p(int x){write(x);putchar(' ');}
int n,head[200001],cnt,nxt[200001],poi[200001],ans,tot[200001];
inline void add(int x,int y){poi[++cnt]=y;nxt[cnt]=head[x];head[x]=cnt;}
inline void Dfs(int x,int dep)
{
	tot[dep]++;
	for(int i=head[x];i;i=nxt[i])
		Dfs(poi[i],dep+1);
}
int main()
{
	n=read();
	For(i,2,n)	add(read(),i);
	Dfs(1,0);
	For(i,1,n)	if(tot[i]&1)	ans++;
	writeln(ans+1);
}

B.Game with String

题意:有一个字符串,随机挑选一个k,将k+1~n放到最前面。新字符串告诉你第一个字符,你可以随意打开一个别的字符,问你这两个字符可以确定k的概率


记录dp[i][j][t]表示第一个字符为i,选到的字符为j=S[t],有多少个这样的k

然后乱搞一波就好了

#include
#include
#include
#include
#include
#include
#include
#include
#define For(i,j,k)	for(int i=j;i<=k;++i)
#define Dow(i,j,k)	for(int i=k;i>=j;--i)
#define ll long long
#define inf 1e9
using namespace std;
inline int read()
{
	int t=0,f=1;char c=getchar();
	while(!isdigit(c))	{if(c=='-')	f=-1;c=getchar();}
	while(isdigit(c))	t=t*10+c-'0',c=getchar();
	return t*f;
}
inline void write(int x){if(x>=10)	write(x/10);putchar(x%10+'0');}
inline void writeln(int x){write(x);puts("");}
inline void write_p(int x){write(x);putchar(' ');}
int n,ans,mx,tmp;
int dp[26][26][5001];
char s[20001];
int main()
{
	scanf("%s",s+1);
	n=strlen(s+1);
	For(i,1,n)	s[i+n]=s[i];
	For(i,1,n)
		For(j,1,n-1)//i号,挑选i+j
			dp[s[i]-'a'][s[i+j]-'a'][j]++;
	For(p1,0,25)
	{
		mx=0;
		For(k,1,n-1)
		{
			tmp=0;
			For(p2,0,25)
				if(dp[p1][p2][k]==1)	tmp++;
			mx=max(mx,tmp);
		}
		ans+=mx;
	}
	printf("%.20lf",1.0*ans/n);
}

C.Teodor is not a liar!

挺有意思的一道题

题意:给你n条线段。保证没有一个点被所有线段覆盖。而有个人不信,他不知道有多少个线段,每次他可以询问一个点被多少线段覆盖,问你他最多问几次就会信了


记录cnt[i]表示i被多少线段覆盖

如果有一个点被所有线段覆盖,那么得到的cnt[i]一定是一个单峰函数

自己画一画就知道了

所以问题转化为他最多问几次会发现这个cnt[i]并不是一个单峰函数,所以我们要找的就是找到一个极大的集合使它满足是单峰函数

然后就随便做了

#include
#include
#include
#include
#include
#include
#include
#include
#define For(i,j,k)	for(int i=j;i<=k;++i)
#define Dow(i,j,k)	for(int i=k;i>=j;--i)
#define ll long long
#define inf 1e9
using namespace std;
inline int read()
{
	int t=0,f=1;char c=getchar();
	while(!isdigit(c))	{if(c=='-')	f=-1;c=getchar();}
	while(isdigit(c))	t=t*10+c-'0',c=getchar();
	return t*f;
}
inline void write(int x){if(x>=10)	write(x/10);putchar(x%10+'0');}
inline void writeln(int x){write(x);puts("");}
inline void write_p(int x){write(x);putchar(' ');}
int n,m,x[200001],y[200001],cnt[200001],ans,L=1e9,R,t[200001],mx,tr[200001];
int dp[200001],dp1[200001];
inline void Add(int x,int v){for(;x<=n;x+=x&-x)	tr[x]=max(tr[x],v);}
inline int Ask(int x){int tmp=0;for(;x;x-=x&-x)	tmp=max(tmp,tr[x]);return tmp;}
int main()
{
	n=read();m=read();
	For(i,1,n)	x[i]=read(),y[i]=read();
	For(i,1,n)	t[x[i]]++,t[y[i]+1]--;
	int tmp=0;
	For(i,1,m)	tmp+=t[i],cnt[i]=tmp,mx=max(mx,cnt[i]);
	For(i,1,m)	if(mx==cnt[i])	L=min(L,i),R=max(R,i);
	For(i,1,m)
	{
		dp[i]=Ask(cnt[i]+1)+1;
		Add(cnt[i]+1,dp[i]);
	}		
	For(i,1,n)	tr[i]=0;
	Dow(i,1,m)
	{
		dp1[i]=Ask(cnt[i]+1)+1;
		Add(cnt[i]+1,dp1[i]);
	}	
	For(i,1,m-1)	ans=max(ans,dp[i]+dp1[i+1]);
	writeln(ans);
}

D.Game with Tokens

神题.....

题面:棋盘上有n个黑子,一个白子。每回合所有棋子必须往移动一步,白子先动。白子移动后不能在黑子上,黑子随便动,可以踩在白子上或者踩在黑子上,白子上有黑子并没有关系它依然可以移动。白子不能走则黑子胜,若白子可以走出10^100500步则黑子负,问有多少个位置放白子,黑子必胜


看到题目完全没思路。。。。

只知道10^100500=inf(。。。

于是看了题解


对于一个黑子,他的影响范围://图转自cf官方题解

Codeforces Round #468 Div1 A~D解题报告_第1张图片

首先对图黑白染色,显然同色的棋子互相堵不到

接下来考虑单个黑子

这个黑子可以让所有绿色的位置上的白子不能往右,蓝子不能往下。稍微yy一下发现是显然的

所以题目变成了问有多少个位置   对于n个黑点,成为过四种颜色至少一次


好像会做了??

好像还是不会。。。

斜着的很难搞,想到旋转坐标系

把(x,y)改成(x+y,x-y)

这样之后的图变成了

Codeforces Round #468 Div1 A~D解题报告_第2张图片


接下来我们维护四个数组,ul[i]  表示i这一行蓝子的左边界,以此类推

显然ul[i]=上面所有黑子的y坐标最小值

维护一下这个东西,就可以做了

#include
#include
#include
#include
#include
#include
#include
#include
#define For(i,j,k)	for(int i=j;i<=k;++i)
#define Dow(i,j,k)	for(int i=k;i>=j;--i)
#define ll long long
#define inf 1e9
#define fir first
#define sec second
#define pb push_back
#define mk make_pair
#define pa pair
using namespace std;
inline int read()
{
	int t=0,f=1;char c=getchar();
	while(!isdigit(c))	{if(c=='-')	f=-1;c=getchar();}
	while(isdigit(c))	t=t*10+c-'0',c=getchar();
	return t*f;
}
inline void write(int x){if(x>=10)	write(x/10);putchar(x%10+'0');}
inline void writeln(int x){write(x);puts("");}
inline void write_p(int x){write(x);putchar(' ');}
int n,x,y;
int dr[500001],dl[500001],ul[500001],ur[500001];
ll ans=0;
vector vec[2];
inline void Solve(int p)
{
	memset(ur,0,sizeof ur);memset(ul,0x3f,sizeof ul);
	memset(dr,0,sizeof dr);memset(dl,0x3f,sizeof dl);
	for(int i=0;i


你可能感兴趣的:(题库,其他,Codeforces)