NOIP2014题解

NOIP2014题解

Day1

生活大爆炸版石头剪刀布 rps

简单模拟题,注意细节

#include<iostream>
#include<cstdio>
using namespace std;
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int ans[5][5]={0,-1,1,1,-1,1,0,-1,1,-1,-1,1,0,-1,1,-1,-1,1,0,1,1,1,-1,-1,0};
int n,na,nb,a[500],b[500],A,B;
int main()
{
	n=read();na=read();nb=read();
	for(int i=0;i<na;++i)a[i]=read();
	for(int i=0;i<nb;++i)b[i]=read();
	for(int i=0;i<n;++i)
	{
		int d=ans[a[i%na]][b[i%nb]];
		if(d==1)A+=1;if(d==-1)B+=1;
	}
	printf("%d %d\n",A,B);
	return 0;
}

可以说非常简单了,先算出每个点周围点的权值和,在计算它们的平方和。

答案就是权值和的平方减去平方和。

#include<iostream>
#include<cstdio>
using namespace std;
#define MOD 10007
#define MAX 200200
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
struct Line{int v,next;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int n,W[MAX],ans,S[MAX],SS[MAX];
int main()
{
	n=read();
	for(int i=1;i<n;++i)
	{
		int u=read(),v=read();
		Add(u,v);Add(v,u);
	}
	for(int i=1;i<=n;++i)W[i]=read();
	for(int u=1;u<=n;++u)
	{
		int mx=0,mxx=0;
		for(int i=h[u];i;i=e[i].next)
		{
			int v=e[i].v;S[u]=(S[u]+W[v])%MOD;SS[u]=(SS[u]+W[v]*W[v])%MOD;
			if(W[v]>mx)mxx=mx,mx=W[v];
			else if(W[v]>mxx)mxx=W[v];
		}
		ans=max(ans,mx*mxx);
	}
	printf("%d ",ans);
	ans=0;
	for(int i=1;i<=n;++i)ans=(ans+S[i]*S[i])%MOD;
	for(int i=1;i<=n;++i)ans=(ans+MOD-SS[i])%MOD;
	printf("%d\n",ans);
	return 0;
}

飞扬的小鸟 bird

不错的\(dp\)题。

\(f[i][j]\)表示到达\((i,j)\)位置的最小步数。

转移很显然,类似背包可以不用枚举向上飞的次数。

注意先转移向上飞,因为你至少要飞一次,所以先从\(i-1\)转移飞一次,再在\(i\)行内背包转移。

转移完之后再转移下降的情况。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAX 10010
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int n,m,K,L[MAX],H[MAX],X[MAX],Y[MAX];
int f[MAX][1010],inf;
void cmin(int &x,int y){if(x>y)x=y;}
int main()
{
	n=read();m=read();K=read();
	for(int i=1;i<=n;++i)X[i]=read(),Y[i]=read();
	for(int i=1;i<=n;++i)L[i]=0,H[i]=m+1;
	for(int i=1;i<=K;++i)
	{
		int p=read();
		L[p]=read();H[p]=read();
	}
	memset(f,63,sizeof(f));inf=f[0][0];
	for(int i=1;i<=m;++i)f[0][i]=0;
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=m;++j)
			cmin(f[i][min(j+X[i],m)],f[i-1][j]+1);
		for(int j=1;j<=m;++j)
			cmin(f[i][min(j+X[i],m)],f[i][j]+1);
		for(int j=1;j<=m-Y[i];++j)
			cmin(f[i][j],f[i-1][j+Y[i]]);
		for(int j=1;j<=L[i];++j)f[i][j]=inf;
		for(int j=H[i];j<=m;++j)f[i][j]=inf;
	}
	int mn=inf;
	for(int j=1;j<=m;++j)
		if(f[n][j]<1e9)
			mn=min(mn,f[n][j]);
	if(mn>1e9)
	{
		for(int i=n-1;i;--i)
			for(int j=1;j<=m;++j)
				if(f[i][j]<1e9)
				{
					int sum=0;puts("0");
					for(int k=1;k<=i;++k)
						if(H[k]<=m)++sum;
					printf("%d\n",sum);
					return 0;
				}
	}
	else printf("1\n%d\n",mn);
	return 0;
}

Day2

无线网络发射器选址 wireless

暴力

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 150
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int s[MAX][MAX];
int d,n,ans=0,way=0;
int main()
{
	d=read();n=read();
	for(int i=1;i<=n;++i)
	{
		int x=read(),y=read(),k=read();
		s[x][y]+=k;
	}
	for(int i=0;i<=128;++i)
		for(int j=0;j<=128;++j)
		{
			int ss=0;
			for(int k=max(0,i-d);k<=128&&k<=i+d;++k)
				for(int l=max(0,j-d);l<=128&&l<=j+d;++l)
					ss+=s[k][l];
			if(ans<ss)ans=ss,way=1;
			else if(ans==ss)way+=1;
		}
	printf("%d %d\n",way,ans);
	return 0;
}

寻找道路 road

沿着反边\(dfs\)一遍找到所有合法点,再\(bfs\)一遍求答案。实际上只需要存反边就好了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define MAX 10100
#define MAXL 200200
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int n,m,S,T;
struct Line{int v,next;}e[MAXL<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
bool vis[MAX],book[MAX];
void dfs(int u)
{
	if(vis[u])return;vis[u]=true;
	for(int i=h[u];i;i=e[i].next)
		if(!(i&1))dfs(e[i].v);
}
int dis[MAX];
void bfs()
{
	memset(dis,63,sizeof(dis));
	queue<int> Q;Q.push(S);dis[S]=0;
	while(!Q.empty())
	{
		int u=Q.front();Q.pop();
		for(int i=h[u];i;i=e[i].next)
			if((i&1)&&dis[u]+1<dis[e[i].v])
			{
				if(!book[e[i].v])continue;
				dis[e[i].v]=dis[u]+1;
				Q.push(e[i].v);
			}
	}
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=m;++i)
	{
		int u=read(),v=read();
		Add(u,v);Add(v,u);
	}
	S=read(),T=read();
	dfs(T);
	for(int u=1;u<=n;++u)
	{
		bool fl=true;
		for(int i=h[u];i;i=e[i].next)
			if((i&1)&&!vis[e[i].v]){fl=false;break;}
		book[u]=fl;
	}		
	if(!book[S]){puts("-1");return 0;}
	bfs();printf("%d\n",dis[T]);
	return 0;
}

解方程 equation

显然没法直接算,所以我们取个模。显然一个模数很假,所以我们多搞几个模数。

显然\(x\)大于模数就不用重复算,所以我们对于每个模数预处理。

然后枚举就做完了。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int p[]={10007,10013,10017,10023,10029,10037,10097};
int a[7][105];
char ch[10100];
int n,m;
void get(int id)
{
	int l=strlen(ch+1);
	for(int i=0;i<7;++i)
	{
		int x=0,fr=1;bool fl=false;
		if(ch[1]=='-')fl=true,fr=2;
		for(int j=fr;j<=l;++j)
			x=(x*10+ch[j]-48)%p[i];
		if(fl)x=(p[i]-x)%p[i];
		a[i][id]=x;
	}
}
int Calc(int id,int x)
{
	int ret=0;
	for(int i=0,X=1;i<=n;++i,X=X*x%p[id])
		ret=(ret+X*a[id][i])%p[id];
	return ret;
}
bool vis[7][20000];
int S[1000100],top;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<=n;++i)scanf("%s",ch+1),get(i);
	for(int i=0;i<7;++i)
		for(int j=0;j<p[i];++j)
			if(Calc(i,j)==0)vis[i][j]=true;
	for(int i=1;i<=m;++i)
	{
		bool fl=true;
		for(int j=0;j<7;++j)if(!vis[j][i%p[j]])fl=false;
		if(fl)S[++top]=i;
	}
	printf("%d\n",top);
	for(int i=1;i<=top;++i)printf("%d\n",S[i]);
	return 0;
}
posted @ 2018-11-08 16:03  小蒟蒻yyb  阅读(522)  评论(0编辑  收藏  举报