NOIP2014模拟 8.13

今天这套题是需要反省的,因为前三题在考试时我的第一思路出得很快,而且居然和正解一样,却在最后只AC了第三题。十分可惜,也需要沉重反省。。。


Span (Standard IO)

Time Limits: 1000 ms  Memory Limits: 128000 KB     
Description
  某国有N个村子,M条道路,为了实现“村村通工程”现在要”油漆”N-1条道路(因为某些人总是说该国所有的项目全是从国外进口来的,只是漆上本国的油漆罢了),因为“和谐”是此国最大的目标和追求,以致于对于最小造价什么的都不在乎了,只希望你所选出来的最长边与最短边的差越小越好。
Input
  第一行给出一个数字TOT,代表有多少组数据,Tot<=6
  对于每组数据,首先给出N,M
  下面M行,每行三个数a,b,c代表a村与b的村道路距离为c.
Output
  输出最小差值,如果无解输出”-1”.
Sample Input
1
4 5
1 2 3
1 3 5
1 4 6
2 4 6
3 4 7

Sample Output
1
Data Constraint
Hint
【样例解释】
  选择1-4,2-4,3-4这三条边.
【数据范围】
  1:2 ≤ n ≤ 100 and 0 ≤ m ≤ n(n − 1)/2
  2:每条边的权值小于等于10000

  3:保证没有自环,没有重边


一开始想到就是枚举最短边kruskal。但想想似乎复杂度O(tot*m^2)过不了。于是,我开始探究更高深的方法。

最后,觉得这复杂度只允许我贪心了,或许贪心就是正解,当然,我自己都觉得自己策略不好,但我像中了邪一般去赌一把。这就是挂科的根本原因。


最后看到正解,我跪了,居然就是枚举。

这次教训告诉我,唯稳方能胜,不要去做没把握的事。


无聊的草稿 (Standard IO)
Time Limits: 3000 ms  Memory Limits: 128000 KB     
Goto ProblemSet


Description
  图中有N个点,每两点间只有唯一的路径,对于这样一个给定的图,最大的“毛毛虫”会有多大。毛毛虫包含一条主链,毛毛虫中的节点,要不在主链上,要么和主链上某节点相邻,如下图所示有两只合法的毛毛虫,点数越多,毛毛虫越大。
Input
  输入文件第一行两个整数N,M(N≤1000000)
  接下来M行,每行两个整数a, b(a, b≤N)
  你可以假定没有一对相同的(a, b)会出现一次以上。
Output
  一个整数ans,表示最大的毛毛虫的大小。
Sample Input
5 4
1 2
1 3
4 1
5 1
Sample Output
5
Data Constraint

Hint



【数据规模】
  1. 对于20%的数据,N≤200
  2. 对于40%的数据,N≤5000
  3. 对于100%的数据,N≤10^6


当时看到题目第一反应是最长链时,因为第一题的题目描述激发了我丰富的想象力,早在做第一题时,我海里就已荡漾着最长链这个东西。但是,我却先去做了第三题。而第一题的猥琐方法耗费了不少时间。后面所剩不多的时间虽然够打完这题,但我去检验第三题了。


考完后,当我看到最长链是正解时,我和我的小心脏都惊呆了。


以下是我ac的程序

#include
   
   
    
    
#include
    
    
     
     
#include
     
     
      
      
using namespace std;
struct link{
	int l,y;
}f[2000001];
int i,j,k,x,y,n,m,g[1000001],dep,ans,q[1000001],se[1000001],d[1000001];
bool v[1000001];

void dfsI(int p,int sum,int dep){
	int i,j,k;
	k=g[p];
	q[dep]=p;
	v[p]=0;
	if(dep==1)j=d[p];else j=d[p]-1;
	
	while(k){
		if(v[f[k].y])dfsI(f[k].y,sum+j,0);
		k=f[k].l;
	}
	if(sum>ans)ans=sum,x=p;
}

int main(){
	scanf("%d%d",&n,&m);
	int tot=0;
	for(i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		f[++tot].y=y;
		f[tot].l=g[x];
		g[x]=tot;
		f[++tot].y=x;
		f[tot].l=g[y];
		g[y]=tot;
		d[x]++;d[y]++;	
	}
	memset(v,1,sizeof(v));
	ans=0;
	dfsI(1,1,1);
	memset(v,1,sizeof(v));
	ans=0;
	dfsI(x,1,1);
	printf("%d",ans);
}

     
     
    
    
   
   

锻炼身体 (Standard IO)
Time Limits: 1000 ms  Memory Limits: 128000 KB     

Description

  胖子很有钱。他购买了一个先进的跑步机(真的不一样哦~~~~)。
  这个跑步机是这样的:
  1. 可以把它看成一个N*M的矩阵。有的格子是障碍不能经过(用x表示),有的格子是空地可以经过(用.表示)。
  2. 对于每一个时段,跑步机有不同的倾斜方向。由于胖子太胖了,所以他这个时候只有2种选择:要么沿这个方向移动(每秒移动1个格子),或者艰难的保持在原来的位置不动。
  现在胖子已经设定好了跑步机在不同时段中的倾斜方向。众所周知,保持在原地不动是不会做功的。胖子要减肥就要做功。所以他想知道他最多能够跑多长的路程。

Input

  第一行5个正整数N,M,X,Y,K。 X,Y是胖子的初始位置,数据保证这个点不是障碍。
  接下来N行,每行M个字符,表示跑步机上的地形。
  最后K行,每行3个正整数S,T,W。S表示这个时段的开始时间,T(T<=10000)表示这个时段的结束时间。W表示该时段的倾斜方向。(1:上 2:下 3:左 4:右)

Output

  一个整数LEN,表示胖子最多可以跑动的距离。

Sample Input
4 5 4 1 3
..xx.
.....
...x.
.....
1 3 4
4 5 1
6 7 2
Sample Output
6

【数据范围】
  对于60%的数据 N,M<=80 K<=50
  对于100%的数据 N,M<=200,K<=200

这题打的时候我还边打边加防止粗心的注释,最后打的也挺细心的。这次唯一的优点要发扬光大啊、、、

Dp

F[i][x][y]指在时段i,(x,y)点的最大做功。

明显F[i][x][y]=max(F[i][x][y],F[i][x][k]+Abs(y-k))//举例:当倾斜向左右上时,行号不变,列号 y-k>Ti-Si+1.

看到这条会超时的方程如此华丽,搞得我忍不住去优化一下它了。

设    F[i][x][j]+y-j>F[i][x][k]+y-k

F[i][x][j]-F[i][x][k]>j-k

于是可以用这个不等式建单调队列优化Dp,然后就ac了。

附上代码::

#include
   
   
    
    
#include
    
    
     
     
#include
     
     
      
      
#include
      
      
       
       
using namespace std;

struct node{
	int s,t,w;
}s[202];

int i,j,k,x,y,n,m,q/*[2]*/[202][2],f[202][202][202];
bool v[202][202];
char e;

bool cmp(node a , node b){
	return a.s
       
       
         =1;y--){ int l=2,r=1; for(x=n;x>=1;x--){//sidejugdeCaution if(v[x][y]){ l=2;r=1; q[l][1]=-1; continue; } while(abs(x-q[l][0])>s[i].t-s[i].s+1&&l<=r)l++; if(f[i-1][x][y]!=-1){ while(f[i-1][x][y]-q[r][1]>abs(x-q[r][0])&&r>=l)r--; r++; q[r][1]=f[i-1][x][y]; q[r][0]=x; } if(q[l][1]!=-1&&l<=r)f[i][x][y]=q[l][1]+abs(x-q[l][0]); } } if(s[i].w==2) for(y=m;y>=1;y--){ int l=2,r=1; for(x=1;x<=n;x++){//sidejugdeCaution if(v[x][y]){ l=2;r=1; q[l][1]=-1; continue; } while(abs(x-q[l][0])>s[i].t-s[i].s+1&&l<=r)l++; if(f[i-1][x][y]!=-1){ while(f[i-1][x][y]-q[r][1]>abs(x-q[r][0])&&r>=l)r--; r++; q[r][1]=f[i-1][x][y]; q[r][0]=x; } if(q[l][1]!=-1&&l<=r)f[i][x][y]=q[l][1]+abs(x-q[l][0]); } } if(s[i].w==3) for(x=n;x>=1;x--){ int l=2,r=1; for(y=m;y>=1;y--){//sidejugdeCaution if(v[x][y]){ l=2;r=1; q[l][1]=-1; continue; } while(abs(y-q[l][0])>s[i].t-s[i].s+1&&l<=r)l++; if(f[i-1][x][y]!=-1){ while(f[i-1][x][y]-q[r][1]>abs(y-q[r][0])&&r>=l)r--; r++; q[r][1]=f[i-1][x][y]; q[r][0]=y; } if(q[l][1]!=-1&&l<=r)f[i][x][y]=q[l][1]+abs(y-q[l][0]); } } if(s[i].w==4) for(x=n;x>=1;x--){ int l=2,r=1; for(y=1;y<=m;y++){//sidejugdeCaution if(v[x][y]){ l=2;r=1; q[l][1]=-1; continue; } while(abs(y-q[l][0])>s[i].t-s[i].s+1&&l<=r)l++; if(f[i-1][x][y]!=-1){ while(f[i-1][x][y]-q[r][1]>abs(y-q[r][0])&&r>=l)r--; r++; q[r][1]=f[i-1][x][y]; q[r][0]=y; } if(q[l][1]!=-1&&l<=r)f[i][x][y]=q[l][1]+abs(y-q[l][0]); } } memset(q,255,sizeof(q)); } int ans; ans=0; for(i=1;i<=n;i++) for(j=1;j<=m;j++){ ans=max(ans,f[k][i][j]); } printf("%d",ans); } 
       
      
      
     
     
    
    
   
   


总而言之,这次虽然挂的这么惨,但是也积累了不少考试时做题的经验,原则,和一些习惯。希望挂着挂着挂多了就不挂了。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值