10-18考试记

10-18考试记

300分。开心。

1、咒语

【题目描述】
亮亮梦到自己来到了魔法城堡,但一扇巨大的石门阻拦了他通向城堡内的路。
正当他沮丧之际,突然发现门上有一处机关,机关上有一张很长的纸条。
亮亮拿起纸条的一端,只见上面写着打开机关的方法:“打开机关需要念动
符咒,咒语是一串长为 L 的由 0 和 1 组成的字符串。在这张长纸条上列了 n 个
长为 L 的字符串,正确的咒语即是在纷繁的 2^L 种字符串中,与这些纸条上的
字符串相异度之和最小,并且在满足这一条件下,0 的个数最多的字符串。两个
字符串的相异度定义为对应位置不相等的字符对的个数。如‘011’和‘001’的
相异度为 1,因为它们有且只有第二个位置上的字符不相等。”
亮亮拉起纸条,只觉得纸条似乎永远也拉不完。这上面有着数以万计的字符
串,而每一个字符串的长度也或百或千,以人力看来是无法得到正确的咒语。你
能帮帮他,让他得以进入魔法城堡,一窥其中的奥秘吗?
【输入格式】
第一行为一个数字 N 。
接下来的 N 行,每行为一个长为 L 的 01 字符串。数据保证 N 个字符串等长。
【输出格式】
只有一行,是一个长为 L 的字符串 S,即为正确的咒语。

记录每一位有多少个1就行了。

code:

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int wx=3017;

inline int read(){
	int sum=0,f=1; char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
	return sum*f;
}

char c[wx][wx];
int l[wx];
int n;


//l[i]表示i这一位有多少个1
//如果这一位的1个数多于0,那么这一位答案为1
//否则为0 
//暴力打不出来。。。

//SB吧打啥暴力 

int main(){
	freopen("curse.in","r",stdin);
	freopen("curse.out","w",stdout);
	
	n=read();
	for(int i=1;i<=n;i++)scanf("%s",c[i]+1);
	int len=strlen(c[1]+1);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=len;j++){
			if(c[i][j]=='1')l[j]++;
		}
	} 
	for(int i=1;i<=len;i++){
		if(l[i]<=(n-l[i]))printf("0");
		else printf("1");
	}
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}

2、神光

【题目描述】
亮亮成功地念出了咒语,石门缓缓地自动移开,一道道绚丽的神光从城堡内
激射而出。亮亮好奇而又兴奋地走入了城堡中,迎面有一座极长的魔法阵。
魔法阵可以看作一条直线,它被均匀地分成了 1 000 000 000 个位置,一个位
置可以看成是一个格子。有些位置上筑有法坛,一共 N 座。亮亮只有破了眼前
的魔法阵,才能继续前进,而欲破法阵,必须毁掉所有的法坛。
亮亮身前有两根法杖:一根颜色血红,能发红色神光,光芒可以笼罩连续 L
个位置,并摧毁这 L 个位置上所有的法坛,最多使用 R 次;另一根颜色碧绿,
能发绿色神光,光芒可以笼罩连续 2L 个位置,并摧毁这 2L 个位置上所有的法
坛,最多使用 G 次。
法杖的神奇之处在于,L 的值必须由亮亮事先设定好,并且一经设定,便无
法更改。亮亮需要在规定的次数下摧毁所有法坛,并且使得 L 最小。
【输入格式】
第一行三个整数 N, R, G。
第 i (2<=i<=n+1) 行一个整数Ai,表示第 i 座法坛的位置。
【输出格式】
只有一个整数,表示 L 的最小值。

发现数据里的线索 缩小一下DP就可以了。

这个DP的思路还是不错的。

code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int wx=3017;

inline int read(){
	int sum=0,f=1; char ch=getchar();
	while(ch<='0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
	return sum*f;
}

int pos[wx],f[wx][wx];
int rr[wx],gg[wx];
int n,R,G,ans;

//二分?
//这数据范围真TM神了
//不太对,R+G>N直接有解1完事。
//OK DP+二分吧 

bool ok(int L){
	memset(f,0,sizeof f);
	memset(rr,0,sizeof rr);
	memset(gg,0,sizeof gg);
	rr[n+1]=n; gg[n+1]=n;
	for(int i=1;i<=n;i++){
		rr[i]=upper_bound(pos+1,pos+1+n,pos[i]+L-1)-pos-1;
		gg[i]=upper_bound(pos+1,pos+1+n,pos[i]+L*2-1)-pos-1;
	}
	for(int i=0;i<=R;i++){
		for(int j=0;j<=G;j++){
			if(i)f[i][j]=max(f[i][j],rr[f[i-1][j]+1]);
			if(j)f[i][j]=max(f[i][j],gg[f[i][j-1]+1]);
		}
	}
	if(f[R][G]==n)return true;
	return false;
}

int main(){
	freopen("light.in","r",stdin);
	freopen("light.out","w",stdout);
	
	n=read();R=read();G=read();
	for(int i=1;i<=n;i++)pos[i]=read();
	if(R+G>n){
		puts("1");
		return 0;
	}
	sort(pos+1,pos+1+n);
	int l=1; int r=pos[n]-pos[1]+1;
	while(l<=r){
		int mid=l+r>>1;
		if(ok(mid))ans=mid,r=mid-1;
		else l=mid+1;
	}
	printf("%d\n",ans);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
/*
2zz3
2zz3
3zz3
1zz2
2zz2
3zz3
1zz1
2zz2
3zz3
1zz1
2zz2
3zz3
1zz2
2zz2
3zz3
*/

3、迷宫

【题目描述】
破了魔法阵后,亮亮进入了一座迷宫。这座迷宫叫做“梦境迷宫”,亮亮只
有走出这座迷宫,才能从睡梦中醒来。
梦境迷宫可以用无向图来表示。它共有 n 个点和 m 条双向道路,每条道路
都有边权,表示通过这条道路所需的时间,且每条道路可以多次经过。亮亮位于
一号点,而出口则是 n 号点。原本,亮亮该找到一条最短路,快速冲出迷宫,然
而,梦境迷宫的特殊之处在于,如果沿着最短路到达出口,亮亮就会永远陷入梦
境。因此,亮亮必须寻找一条次短路。次短路的长度须严格大于最短路(可以有
多条)的长度,同时又不大于所有除最短路外的道路的长度。
你的任务,就是编写一个程序,帮助亮亮找到通向出口的次短路。
【输入格式】
第一行有两个整数 n、m,表示迷宫内共有 n 个点,m 条边。
接下来 m 行,每行三个整数 x、y、z,表示结点 x 和 y 之间连有一条边权为
z 的无向边。

两边Dij,再枚举边就可以了。

code:

#include <iostream>
#include <cstdio>
#include <queue>

#define int long long

using namespace std;

const int wx=500177;

inline int read(){
	int sum=0,f=1; char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();}
	return sum*f;
}

int n,m,ans=0x7fffffff;
int num;
int head[wx],diss[wx],dist[wx],vis[wx];

struct e{
	int nxt,to,dis;
}edge[wx*2];

void add(int from,int to,int dis){
	edge[++num].nxt=head[from];
	edge[num].to=to;
	edge[num].dis=dis;
	head[from]=num;
}

struct node{
	int u,d;
	friend bool operator < (const node & a,const node & b){
		return a.d>b.d;
	}
};

priority_queue<node > q;

void Dijs(){
	for(int i=1;i<=n;i++)diss[i]=0x7fffffff,vis[i]=0;
	q.push((node){1,0});diss[1]=0;
	while(q.size()){
		int u=q.top().u; q.pop();
		if(vis[u])continue; vis[u]=1;
		for(int i=head[u];i;i=edge[i].nxt){
			int v=edge[i].to;
			if(diss[v]>diss[u]+edge[i].dis){
				diss[v]=diss[u]+edge[i].dis;
				q.push((node){v,diss[v]});
			}
		}
	}
}

void Dijt(){
	for(int i=1;i<=n;i++)dist[i]=0x7fffffff,vis[i]=0;
	q.push((node){n,0});dist[n]=0;
	while(q.size()){
		int u=q.top().u; q.pop();
		if(vis[u])continue; vis[u]=1;
		for(int i=head[u];i;i=edge[i].nxt){
			int v=edge[i].to;
			if(dist[v]>dist[u]+edge[i].dis){
				dist[v]=dist[u]+edge[i].dis;
				q.push((node){v,dist[v]});
			}
		}
	}
}

void work(){
	int beg=diss[n];
	for(int u=1;u<=n;u++){
		for(int i=head[u];i;i=edge[i].nxt){
			int v=edge[i].to;
			int tmp=diss[u]+dist[v]+edge[i].dis;
			if(tmp>beg&&tmp<ans)ans=tmp;
		}
	}
}

//。。。T3是傻逼题 

signed main(){
	freopen("maze.in","r",stdin);
	freopen("maze.out","w",stdout);
	
	n=read(); m=read();
	for(int i=1;i<=m;i++){
		int x,y,z;
		x=read(); y=read(); z=read();
		add(x,y,z); add(y,x,z);
	}
	Dijs();
	Dijt();
	work();
	printf("%lld\n",ans);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}

继续加油。

posted @ 2018-10-18 11:04  _王小呆  阅读(253)  评论(1编辑  收藏  举报