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

10 篇文章 0 订阅
1 篇文章 0 订阅

D题好假E题更假

A.Peculiar apple-tree

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


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

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

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#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<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#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<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#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官方题解


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

接下来考虑单个黑子

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

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


好像会做了??

好像还是不会。。。

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

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

这样之后的图变成了



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

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

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

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#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<int,int>
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<pa> 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<vec[p].size();++i)
	{
		ur[vec[p][i].fir]=dr[vec[p][i].fir]=max(ur[vec[p][i].fir],vec[p][i].sec);
		ul[vec[p][i].fir]=dl[vec[p][i].fir]=min(ul[vec[p][i].fir],vec[p][i].sec);
	}	
	For(i,1,400000)dl[i]=min(dl[i],dl[i-1]),dr[i]=max(dr[i],dr[i-1]);
	Dow(i,0,399999)ul[i]=min(ul[i],ul[i+1]),ur[i]=max(ur[i],ur[i+1]);
	For(i,0,400000)	if(i&1)	ans+=max(0,min(dr[i],ur[i])/2-max(dl[i],ul[i])/2);	
}
int main()
{
	n=read();
	For(i,1,n)
	{
		x=read();y=read();
		if((x+y)&1)	x--,vec[1].pb(mk(x+y+200000,x-y+200000));else	vec[0].pb(mk(x+y+200000,x-y+200000));
	}
	Solve(1);Solve(0);
	cout<<ans<<endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值