• 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
    ",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
    ",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
    ",sum);
    					return 0;
    				}
    	}
    	else printf("1
    %d
    ",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
    ",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
    ",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
    ",top);
    	for(int i=1;i<=top;++i)printf("%d
    ",S[i]);
    	return 0;
    }
    
  • 相关阅读:
    Java实现 LeetCode 524 通过删除字母匹配到字典里最长单词(又是一道语文题)
    dmalloc arm-linux平台使用
    dmalloc在嵌入式的开发板上的应用
    利用linux的mtrace命令定位内存泄露(Memory Leak)
    Linux C 编程内存泄露检测工具(一):mtrace
    Ubuntu10.04下安装Qt4和创建第一个Qt程序
    UBuntu14.04下安装和卸载Qt5.3.1
    MinGW 与MSVC的区别
    Qt5 编译 & 打包依赖dll发布
    查看gcc/g++默认include路径
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9929649.html
Copyright © 2020-2023  润新知