NOIP2007提高组题解

(D1T1) 统计数字 ((OK))

(D1T2) 字符串的展开 ((OK))

(D1T3) 矩阵取数游戏 ((OK))

(D1T4) 树网的核 ((OK))

就最后一道对着样例调了半个小时,其它题都挺容易的.

(T1)就把序列sort排序然后每个数判断有多少个相同的即可.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
int a[200005];
int main(){
	int n=read();for(int i=1;i<=n;++i)a[i]=read();
	sort(a+1,a+n+1);int i=1;
	while(i<=n){
		int sum=1;
		while(a[i+1]==a[i])++i,++sum;
		printf("%d %d
",a[i],sum);
		++i;
	}
    return 0;
}

(T2)字符串+大模拟.昨晚打了半个多小时,(WA)了三个点,然后今天早上又过来面向数据编程对着数据调了一会,有一种恶心的情况没有考虑到.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
char s[105];int bj[105];
char xx[30]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
char dx[30]={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
char sz[10]={'0','1','2','3','4','5','6','7','8','9'};
int main(){
	int p1,p2,p3;scanf("%d%d%d",&p1,&p2,&p3);
	scanf("%s",s+1);int n=strlen(s+1);
	for(int i=1;i<=n;++i){
		if(s[i]=='-'){
			if(i==1||s[i-1]=='-'){
				printf("-");
				continue;
			}
			--i;
		}//刚开始没考虑这一位就是'-'的情况
		if(s[i+1]!='-'){
			if(!bj[i])bj[i]=1,printf("%c",s[i]);
			continue;
		}
		if(s[i]>='a'&&s[i]<='z'){
			if((s[i+2]<=s[i])||(s[i+2]>='0'&&s[i+2]<='9')){
				if(!bj[i])printf("%c",s[i]),bj[i]=1;
				if(!bj[i+2])printf("-%c",s[i+2]),bj[i+2]=1;
				i+=2;continue;
			}
			if(s[i+2]==s[i]+1){
				if(!bj[i])printf("%c",s[i]),bj[i]=1;
				if(!bj[i+2])printf("%c",s[i+2]),bj[i+2]=1;
				i+=2;continue;
			}
			if(!bj[i])printf("%c",s[i]),bj[i]=1;
			if(p3==1){
				if(p1==1){
					for(int k=s[i]+1;k<=s[i+2]-1;++k)
						for(int j=1;j<=p2;++j)printf("%c",xx[k-'a']);
				}
				if(p1==2){
					for(int k=s[i]+1;k<=s[i+2]-1;++k)
						for(int j=1;j<=p2;++j)printf("%c",dx[k-'a']);
				}
				if(p1==3){
					for(int k=s[i]+1;k<=s[i+2]-1;++k)
						for(int j=1;j<=p2;++j)printf("*");
				}
			}
			else{
				if(p1==1){
					for(int k=s[i+2]-1;k>=s[i]+1;--k)
						for(int j=1;j<=p2;++j)printf("%c",xx[k-'a']);
				}
				if(p1==2){
					for(int k=s[i+2]-1;k>=s[i]+1;--k)
						for(int j=1;j<=p2;++j)printf("%c",dx[k-'a']);
				}
				if(p1==3){
					for(int k=s[i+2]-1;k>=s[i]+1;--k)
						for(int j=1;j<=p2;++j)printf("*");
				}
			}
			if(!bj[i+2])printf("%c",s[i+2]),bj[i+2]=1;
			i+=2;continue;
		}
		if(s[i]>='0'&&s[i]<='9'){
			if((s[i+2]<=s[i])||(s[i+2]>='a'&&s[i+2]<='z')){
				if(!bj[i])printf("%c",s[i]),bj[i]=1;
				if(!bj[i+2])printf("-%c",s[i+2]),bj[i+2]=1;
				i+=2;continue;
			}
			if(s[i+2]==s[i]+1){
				if(!bj[i])printf("%c",s[i]),bj[i]=1;
				if(!bj[i+2])printf("%c",s[i+2]),bj[i+2]=1;
				i+=2;continue;
			}
			if(!bj[i])printf("%c",s[i]),bj[i]=1;
			if(p3==1){
				if(p1==1){
					for(int k=s[i]+1;k<=s[i+2]-1;++k)
						for(int j=1;j<=p2;++j)printf("%c",sz[k-'0']);
				}
				if(p1==2){
					for(int k=s[i]+1;i<=s[i+2]-1;++k)
						for(int j=1;j<=p2;++j)printf("%c",sz[k-'0']);
				}
				if(p1==3){
					for(int k=s[i]+1;i<=s[i+2]-1;++k)
						for(int j=1;j<=p2;++j)printf("*");
				}
			}
			else{
				if(p1==1){
					for(int k=s[i+2]-1;k>=s[i]+1;--k)
						for(int j=1;j<=p2;++j)printf("%c",sz[k-'0']);
				}
				if(p1==2){
					for(int k=s[i+2]-1;k>=s[i]+1;--k)
						for(int j=1;j<=p2;++j)printf("%c",sz[k-'0']);
				}
				if(p1==3){
					for(int k=s[i+2]-1;k>=s[i]+1;--k)
						for(int j=1;j<=p2;++j)printf("*");
				}
			}
			if(!bj[i+2])printf("%c",s[i+2]),bj[i+2]=1;
			i+=2;continue;
		}
	}printf("
");
    return 0;
}

(T3)每一行都是独立的,所以可以分开来做,每一次只能取首尾,所以当前剩下的没取的一定是中间连续的一段,有点类似于区间(DP),设(f[j][k])表示第i行取完了区间([j,k])时的最大得分,则(f[j][k]=max(f[j+1][k]+val[i][j]*2^{m-(k-j)},f[j][k-1]+val[i][k]*2^{m-(k-j)})).

所以初始化就是(f[j][j]=val[i][j]*2^m)

不想写高精,那就用__(int128),毒奶一口(CSP)不考高精.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=85;
int n,m,a[N];
__int128 ans,Base[N],f[N][N];
inline void print(__int128 x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9)print(x/10);
    putchar(x%10+'0');
}
int main(){
	n=read(),m=read();
	Base[0]=1;for(int i=1;i<=m;++i)Base[i]=Base[i-1]<<1;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j)a[j]=read();
		memset(f,0,sizeof(f));
		for(int j=1;j<=m;++j)f[j][j]=Base[m]*a[j];
		for(int len=2;len<=m;++len){
			for(int j=1;j+len-1<=m;++j){
				int k=j+len-1;
				f[j][k]=max(f[j+1][k]+a[j]*Base[m-(k-j)],f[j][k-1]+a[k]*Base[m-(k-j)]);
			}
		}
		ans+=f[1][m];
	}
	print(ans);printf("
");
    return 0;
}

(T4)这道题不久前学树的直径的时候是蓝书上的例题,依稀记得蓝书上讲了好多种方法,今天再做我一眼想到的就是一个比较辣鸡的算法.

预处理出树的直径((dfs)求树的直径可以记录直径上的各种信息),然后枚举树网的核的一个端点,另一个端点能多远就多远(这样一定是最优的),然后这一段就是当前枚举出的树网的核,从核开始(dfs)求出非核上的点到核的最大距离,每次枚举的最大值的最小值就是答案.

之前写的博客写了两种方法.博客

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=305;
int n,s,ans=1<<30;
int d[N][N],dis[N],pre[N],bj[N];
int tot,head[N],nxt[N<<1],to[N<<1],w[N<<1];
queue<int>q;
inline void add(int a,int b,int c){nxt[++tot]=head[a];head[a]=tot;to[tot]=b;w[tot]=c;}
inline void dfs(int u,int fa){
	for(int i=head[u];i;i=nxt[i]){
		int v=to[i];if(v==fa)continue;
		dis[v]=dis[u]+w[i];pre[v]=u;dfs(v,u);
	}
}
inline void DFS(int u,int fa){
	for(int i=head[u];i;i=nxt[i]){
		int v=to[i];if(v==fa||bj[v])continue;
		dis[v]=dis[u]+w[i];DFS(v,u);
	}
}
int main(){
	n=read();s=read();
	for(int i=1;i<n;++i){
		int a=read(),b=read(),c=read();
		add(a,b,c);add(b,a,c);d[a][b]=d[b][a]=c;
	}
	int pos1=0,pos2=0,maxn=0;dfs(1,0);
	for(int i=1;i<=n;++i)if(dis[i]>maxn)maxn=dis[i],pos1=i;
	dis[pos1]=0;dfs(pos1,0);maxn=0;for(int i=1;i<=n;++i)if(dis[i]>maxn)maxn=dis[i],pos2=i;
	pre[pos1]=0;
	for(int rt=pos2;rt!=0;rt=pre[rt]){
		memset(bj,0,sizeof(bj));
		int now=0,j=rt;q.push(j);bj[j]=1;
		while(pre[j]&&now+d[j][pre[j]]<=s){
			now+=d[j][pre[j]];bj[pre[j]]=1;q.push(pre[j]);
			j=pre[j];
		}
		while(q.size()){
			int x=q.front();q.pop();
			dis[x]=0;DFS(x,0);
		}
		int cnt=0;
		for(int i=1;i<=n;++i)cnt=max(cnt,dis[i]);
		ans=min(ans,cnt);
	}
	printf("%d
",ans);
	return 0;
}

原文地址:https://www.cnblogs.com/PPXppx/p/11803115.html