2008Noip-S提高组 题解 #一起加油 #考试不暴零,骗分能AC #C++

题解

题目自己上洛谷找找吧
传送门
1.笨小猴
一眼水题,AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
#include<queue>
#include<algorithm>
#include<stack>
#include<map>
#include<cmath>
#include<list>
#include<ctime>

int maxn[26],maxx=-9999999,minx=9999999,mao[26];
int cnt;
char s[110];

bool check(int x)
{
	if(x==0||x==1) return false;
	for(int i=2;i<=sqrt(x);i++)
	{
		if(x%i==0)
		return false;
	}
	return true;
} 

using namespace std; 
int main()
{
	//freopen("word.in","r",stdin);
	//freopen("word.out","w",stdout);
    
	gets(s);
	int len=strlen(s);
	 for(int i=0;i<len;i++)
	 {
			maxn[s[i]-'a']++;
	 }
	 for(int i=0;i<26;i++)
	{
		
		if(maxn[i]!=0)
		{mao[cnt]=maxn[i];cnt++;}
	}
	sort(mao,mao+cnt);
	minx=mao[0];maxx=mao[cnt-1];
	if(check(maxx-minx)==true)
	{
		 printf("Lucky Word\n");
		 printf("%d",maxx-minx);
		 return 0;
	}
	else 
	{
		
		printf("No Answer\n");
		printf("0");
		return 0;
	}
	return 0;
}

做法:有点像桶排,简单模拟,原创代码(好像就我一个这样做)。

2.火柴棒等式
也是简单的模拟,AC代码:

//Let's AK IOI!!!
//by lmrttx
#include<bits/stdc++.h>
using namespace std;
int num[10]={6,2,5,5,4,5,6,3,7,6};
int n,sum;
int get_match(int x)
{
	int k=0;
	for(int i=x;i!=0;i/=10)
	k+=num[i%10];
	if(x==0)k+=num[0];
	return k;
}
int main()
{
	scanf("%d",&n);
	for(int i=0;i<=1000;i++)
	for(int j=0;j<=1000;j++)
	if(get_match(i)+get_match(j)+get_match(i+j)+4==n)
	sum++;
	printf("%d",sum);
	return 0;
 } 

做法:先用数组表示出每个数字所需的火柴棒个数,然后暴力枚举每两个数相加,很好看懂,其中4表示加号和等号所需的4根火柴棒
3.传纸条
一个还可以的DP
四维也能过
附上三维AC代码:
说明:第一维是 步数,两人步数相同(看作两人同时出发,向对方传纸条)
剩下两维就是其中一人的横坐标和另一人的纵坐标
注意:第一维要开两倍大小,要判断路径是否重合

#include<bits/stdc++.h>
using namespace std;
int f[104][52][52],a[52][52],m,n;
int max_mao(int a1,int a2,int a3,int a4)
{
	if(a1<a2)a1=a2;
	if(a1<a3)a1=a3;
	if(a1<a4)a1=a4;
	return a1;
}
int main()
{
	scanf("%d%d",&m,&n);
	for(int i=1;i<=m;i++)
	 for(int j=1;j<=n;j++)
	  scanf("%d",&a[i][j]);
	  
	  for(int i=1;i<=m+n-1;i++)
	   for(int j=1;j<=m;j++)
	   for(int k=1;k<=m;k++)
	   {
	   		if(i-j<0 || i-k<0)
	   		continue;
	   		f[i][j][k]=max_mao(f[i-1][j][k],f[i-1][j-1][k-1],
			   f[i-1][j-1][k],f[i-1][j][k-1])+a[j][i-j+1]+a[k][i-k+1];
			   if(j==k)//判断路径是否重合,重合减一
			   f[i][j][k]-=a[k][i-k+1];
	   } 
	   printf("%d",f[m+n-1][m][m]);
	   return 0;
 } 

好好想想,挺好理解的

4.双栈排序
这题考二分图+染色
前置知识:二分图+染色
自己去问问度娘
AC代码:

#include<bits/stdc++.h>
using namespace std;
const int INF=99999999;
const int MAXN=1005;
int n,num,color[MAXN],t[MAXN],s[MAXN];
bool flag,e[MAXN][MAXN];

void paint(int x,int c)
{
	color[x]=c;
	for(int i=1;i<=n;i++)
	if(e[x][i])
	{
		if(color[i]==c)flag=false;
		if(!color[i])paint(i,3-c);
	}
}

void make()
{
	s[n+1]=INF;
	for(int i=n;i>=1;i--)
	{
		s[i]=t[i];
		if(s[i+1]<s[i])
		s[i]=s[i+1];
	}
	for(int i=1;i<n;i++)
	for(int j=i+1;j<n;j++)
	if(t[i]<t[j]&&s[j+1]<t[i])
	e[i][j]=e[j][i]=true;
	for(int i=1;i<=n;i++)
	if(!color[i])
	paint(i,1);
}

void work()
{
	if(flag==false)
	{
		printf("0");
		return;
	}
	stack<int> s1,s2;
	int now=1;
	for(int i=1;i<=n;i++)
	{
		if(color[i]==1)
		{
			s1.push(t[i]);
			printf("a ");
		}
		else
		{
			s2.push(t[i]);
			printf("c ");
		}
		while( (!s1.empty()&&s1.top()==now)
		|| (!s2.empty()&&s2.top()==now) )
		{
			if(!s1.empty()&&s1.top()==now)
			{
				s1.pop();
				now++;
				printf("b ");
			}
			else 
			{
				s2.pop();
				now++;
				printf("d ");
			}
		}
	}
}

int main()
{
	flag=true;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	scanf("%d",&t[i]);
	make();work();
	return 0;
} 

为什么用二分图呢???
对数字串进行逐次遍历,如果符合 规则 ,就连线,遍历结束后,自然就有了二分图,然后染色,得到 染色表,借助染色表,完成排序
说真的,不好理解
好好想想吧

结语

快要CSP了
我会写些像这种题解的博客
一起加油迎考!!!

谢谢阅读

©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页