【codeforces #286(div 2)】ABCD题解

这次rank23~又回到紫名啦~


A.枚举插入的位置和插入的字符,暴力判断即可。

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
string S;
int s[20],n[20];
int main()
{
        cin>>S;
	for (int i=0;i<S.length();i++)
		s[i+1]=(int)(S[i]-'a'+1);
	for (int i=1;i<=S.length()+1;i++)
		for (int k=1;k<=26;k++)
		{
			n[i]=k;
			for (int j=1;j<=i-1;j++)
				n[j]=s[j];
			for (int j=i;j<=S.length();j++)
				n[j+1]=s[j];
			int l=1,r=S.length()+1;
			bool f=false;
			while (n[r]==n[l])
			{
				r--,l++;
				if (l>=r) 
				{
					f=true;
					break;
				}
			}
			if (f)
			{
				for (int j=1;j<=S.length()+1;j++)
					cout<<(char)('a'+n[j]-1);
				cout<<endl;
				return 0;
			}
		}
	cout<<"NA"<<endl;
	return 0;
}


B.暴力dfs每一种颜色

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
int tot=0,n,m,h[105],q,de,c[105],v[105];
struct edge
{
	int c,y,ne;
}e[10000];
void Add(int x,int y,int c)
{
	tot++;
	e[tot].y=y;
	e[tot].c=c;
	e[tot].ne=h[x];
	h[x]=tot;
}
void dfs(int x,int now)
{
	if (x==de)
	{
		c[now]=1;
		return;
	}
	for (int i=h[x];i;i=e[i].ne)
	{
		if (e[i].c!=now) continue;
		int y=e[i].y;
		if (!v[y])
		{
			v[y]=1;
			dfs(y,now);
			v[y]=0;
		}
	}
}
int main()
{
        scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	{
		int x,y,co;
		scanf("%d%d%d",&x,&y,&co);
		Add(x,y,co);Add(y,x,co);
	}
	scanf("%d",&q);
	while (q--)
	{
		int x;
		scanf("%d%d",&x,&de);
		memset(v,0,sizeof(v));
		memset(c,0,sizeof(c));
		v[x]=1;
		for (int i=h[x];i;i=e[i].ne)
		{
			int y=e[i].y;
			v[y]=1;
			dfs(y,e[i].c);
			v[y]=0;
		}
		int ans=0;
		for (int i=1;i<=m;i++)
			ans+=c[i];
		cout<<ans<<endl;
	}
	return 0;
}


C.

这道题显然是个dp,但是暴力的dp超时超空间。


仔细观察可以发现最多只有500种步行的长度,比如d=1,假设每次都增加1,不到250就超过30000了;每次减少一步也同理。


这个时候dp就是500*30000了,可以过的。


注意这道题中说超过30000就不能走!!

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#define M 30005
#include <queue>
using namespace std;
struct data
{
	int p,n;
};
int c[M],n,d,f[M][505],b[M],k[M];
int main()
{
	int ma=0;
        scanf("%d%d",&n,&d);
	for (int i=1;i<=n;i++)
	{
		int x;
		scanf("%d",&x);
		c[x]++;
		ma=max(ma,x);
	}
	if (d<=250)
	{
		for (int i=1;i<=d+250;i++)
			b[i]=i,k[i]=i;
	}
	else
	{
		int now=0;
		for (int i=d-250;i<=min(30000,d+250);i++)
			b[++now]=i,k[i]=now;
	}
	memset(f,-1,sizeof(f));
	f[d][k[d]]=c[d];
	int ans=f[d][k[d]];
	for (int i=d;i<=min(ma,30000-1);i++)
		for (int j=1;j<=500;j++)
		{
			if (f[i][j]==-1) continue;
			int m=b[j];
			for (int now=max(m-1,1);now<=m+1;now++)
			{
				int de=i+now;
				if (de>30000) continue;
				f[de][k[now]]=max(f[de][k[now]],f[i][j]+c[de]),
				ans=max(ans,f[de][k[now]]);
			}
		}
	cout<<ans<<endl;
	return 0;
}

考试A了前三个。。


D题看题解明白了:

找每一个连通的块,设块中有x个点。


如果其中没有环,那么这个块要建x-1条边就可以保证全部满足,因为没有环的话,就一定可以拓扑排序,那么把拓扑排序之后的点连成一条链,就可以满足要求。

如果有环的话就要x条边了。


#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
int v[200005],h2[200005],in[200005],h[200005],tot=0,k,n,m;
struct edge
{
	int y,ne;
}e[400005];
queue<int> q;
void Add(int x,int y)
{
	tot++;
	e[tot].y=y;
	e[tot].ne=h[x];
	h[x]=tot;
}
void Add2(int x,int y)
{
	tot++;
	e[tot].y=y;
	e[tot].ne=h2[x];
	h2[x]=tot;
}
void dfs(int x)
{
	if (!in[x]) q.push(x);
	tot++;
	v[x]=1;
	for (int i=h2[x];i;i=e[i].ne)
	{
		int y=e[i].y;
		if (v[y]) continue;
		dfs(y);
	}
}
int main()
{
        scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		Add(x,y);
		Add2(x,y);Add2(y,x);
		in[y]++;
	}
	int ans=0;
	for (int i=1;i<=n;i++)
		if (!v[i]) 
		{
			tot=0;
			k=0;
			while (!q.empty())
				q.pop();
			dfs(i);
			if (tot==1) continue;
			int ok=0;
			while (!q.empty())
			{
				int x=q.front();
				q.pop();
				ok++;
				if (ok>tot) break;
				for (int i=h[x];i;i=e[i].ne)
				{
					in[e[i].y]--;
					if (!in[e[i].y]) q.push(e[i].y);
				}
			}
			if (ok==tot) ans+=(tot-1);
			else ans+=tot;
		}
	cout<<ans<<endl;
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值