2018.02.08【GDOI2018】模拟C组

终于结束了。。。

JZOJ NO.1 【GDOI2005】积木分发

分析

作为最水的一道题。快排需要的积木,从小到大模拟,给不了NO,否则就YES。


代码

#include <cstdio>
#include <algorithm>
#include <cctype>
using namespace std;
struct b{int x,y;}a[10002]; int n; unsigned long long s;
bool cmp(b u,b v){return u.y<v.y;}
unsigned long long in(){
	char c=getchar(); unsigned long long ans=0;
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
bool check(int s){
	for (int i=1;i<=n;i++){
		if (s<a[i].y) return false;//不能帮助
		s+=a[i].x;//收回积木
	} return true;
}
int main(){
	while (n=in(),s=in(),n||s){//记住或者(二十分!)
		for (int i=1;i<=n;i++) a[i].x=in(),a[i].y=in();
		stable_sort(a+1,a+1+n,cmp);
		if (check(s)) puts("YES"); else puts("NO");
	}
	return 0;
} 

JZOJ NO.2 【GDOI2005】电路稳定性

分析

纯模拟,并联电路x×yx×yx×y ,串联电路x+(1−x)×yx+(1-x)×yx+(1x)×y


代码

#include <cstdio>
#include <cstring>
#include <cctype> 
using namespace std;
double a[101],p[27]; char s[101]; int n;
int news(){int m=0; for (int i=1;i<=n;i++) if (a[i]) a[++m]=a[i]; a[m+1]=0; return m;}//把0都去掉
int main(){
	scanf("%d\n",&n);
	scanf("%s",s+1); 
	for (int i=1;i<=n;i++) scanf("%lf",&p[i]); n=strlen(s+1);
	for (int i=1;i<=strlen(s+1);i++){
		if (s[i]=='(') a[i]=-1;//(变成-1
		if (s[i]==')') a[i]=-2;//以此类推
		if (s[i]==',') a[i]=-3;
	 if (isupper(s[i]))a[i]=p[s[i]-64];//大写字母变成它对应的权值
	} 
	while (n>1){
		for (int i=1;i<=n;i++){
			int j=i;
			while (a[j]>0&&a[j-1]!=-3&&a[j+1]==-3&&a[j+2]>0){//串联
				a[j+2]=a[j]+(1-a[j])*a[j+2];//串联公式
				a[j+1]=a[j]=0,j+=2;//变成0
			}
		}
		n=news();//清扫运算过程
		for (int i=2;i<=n;i++){
			int j=i;
			while (a[j-1]==-1&&a[j+1]==-2&&a[j+2]==-1&&a[j+4]==-2){//并联
				a[j+3]*=a[j];//并联公式
				a[j-1]=a[j+1]=a[j]=0,j+=3;
			}
			if (a[j-1]==-1&&a[j+1]==-2&&(a[j+2]==-3||a[j+2]==-2||!a[j+2])) a[j-1]=a[j+1]=0;//删掉括号
		}
		n=news();//清扫运算过程
	}
	printf("%.4lf",a[1]);//剩下一个就是答案
	return 0;
}

JZOJ NO.3 【GDOI2005】飞越原野

分析

广搜,飞行和行走
用一个循环队列存储坐标、能量、答案。
布尔数组存储是否走过,三维,下标为坐标和能量。


代码

#include <cstdio>
using namespace std;
bool v[101][101][101]; char map[101][101];
const int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
struct node{
	int x,y,ans,eneg;
}q[320001];
void bfs(int n,int m,int d){
	int head=0,tail=0;
	node f1,f2;
	f1.x=f1.y=1,f1.ans=0,f1.eneg=d;//一开始初值能量满,坐标起点
	q[++tail]=f1;
	while (head!=tail){
		f1=q[++head];//出队
		head=(head-1)%(32*n*m)+1;
		if (f1.x==n&&f1.y==m) {printf("%d",f1.ans);return;}//到达终点
		for (int i=0;i<4;i++){//走路
			f2.x=f1.x+dx[i]; f2.y=f1.y+dy[i];
			if (f2.x>0&&f2.x<=n&&f2.y>0&&f2.y<=m&&!v[f2.x][f2.y][f1.eneg]&&map[f1.x][f1.y]=='P'){//可以着陆
				f2.ans=f1.ans+1;//步数+1
				f2.eneg=f1.eneg;//能量不变
				v[f2.x][f2.y][f2.eneg]=1;//标记
				q[++tail]=f2;//入队
				tail=(tail-1)%(32*n*m)+1;
			}
		}
		for (int j=2;j<=f1.eneg;j++){//飞行距离
			for (int i=0;i<4;i++){
				f2.x=f1.x+dx[i]*j;
				f2.y=f1.y+dy[i]*j;
				if (f2.x>0&&f2.x<=n&&f2.y>0&&f2.y<=m&&!v[f2.x][f2.y][f1.eneg-j]&&map[f1.x][f1.y]=='P'){//可以着陆
				f2.ans=f1.ans+1;//步数+1
				f2.eneg=f1.eneg-j;//减去消耗的能量
				v[f2.x][f2.y][f2.eneg]=1;
				q[++tail]=f2;//入队
				tail=(tail-1)%(32*n*m)+1;
			    }
			}
		}
	}
	puts("impossible"); return;//不可能到达
}
int main(){
	int n,m,d;
	scanf("%d%d%d\n",&n,&m,&d);
	for (int i=1;i<=n;i++) gets(map[i]+1);
	bfs(n,m,d); return 0;
}

JZOJ NO.4 【GDOI2005】电子眼

分析

一开始看错题目,输出n-1,错了。&_&
原来是树形dp,如果这个路口装,那么与它相连的路口不用装,如果这个路口不装,那么与它相连的路口都要装。


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
int n,f[100001][2],ls[100001],a[200001];
bool v[100001];
int in(){
	char c=getchar(); int ans=0;
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
void dp(int x){
	int s1=1,s2=0;
	for (int i=ls[x-1];i<=ls[x]-1;i++){
		if (!v[a[i]]){
			v[a[i]]=1;//来过。
			dp(a[i]);
			s1+=min(f[a[i]][0],f[a[i]][1]);//装选择最小的
		}
		s2+=f[a[i]][1];//不装其它都要装
	}
	f[x][1]=s1;
	f[x][0]=s2;
}
int main(){
    n=in(); ls[0]=1;
	for (int i=1;i<=n;i++){
		int x=in(); ls[i]=ls[i-1];
		for (int j=ls[i];j<=ls[i]+x-1;j++) a[j]=in();
		ls[i]+=x;} //ls存储每个路口的路占用的位置
	v[1]=1; dp(1); 
	printf("%d",min(f[1][0],f[1][1])); return 0;//装和不装的最大值
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值