2018.01.27【GDOI2018】模拟C组

111 篇文章 0 订阅
47 篇文章 0 订阅

这套题我考得不错

JZOJ NO.1 香烟

简单的纯模拟。

#include <cstdio>
using namespace std;
int n,m,ans;
int main(){
	scanf("%d%d",&n,&m); ans=n;//首先答案为香烟数
	while (n/m){//如果可以换香烟蒂头
		ans+=n/m;//增加的香烟数
		n=n/m+n%m;//现有的香烟数
	}
	printf("%d",ans);
	return 0;
}

可是这并不是最好的AC代码。

#include <cstdio>
using namespace std;
int n,m;
int main(){
	scanf("%d%d",&n,&m);
	printf("%d",(n-1)/(m-1)+n);
	return 0;
}

首先原来的香烟数不解释,一个烟= k k k个烟蒂,等于花费 k − 1 k-1 k1个烟蒂,但因为不许和别人借烟,最后一个烟蒂不能用。


JZOJ NO.2 背包问题

分析

用前缀和存起它们的和,再用分组背包。


代码

#include <cstdio>
#include <algorithm>
using namespace std;
int v,m,n[101],a[11][101]; bool f[11][5001];
int main(){
	scanf("%d%d",&v,&m);
	for (int i=1;i<=m;i++){
		scanf("%d",&n[i]);
		for (int j=1;j<=n[i];j++)
		scanf("%d",&a[i][j]),a[i][j]+=a[i][j-1];//前缀和
	} f[0][0]=1;
	for (int i=1;i<=m;i++)
	for (int p=0;p<=v;p++)
	if (f[i-1][p]){ //如果前一组可以用
	f[i][p]=1;//那么该组也可以用
	for (int j=1;j<=n[i];j++)
	for (int k=j;k<=n[i];k++)
	if ((p+a[i][k]-a[i][j-1])<=v)
	f[i][p+a[i][k]-a[i][j-1]]=1;//并附加该组的数据
	} int i;
	for (i=v;i>=1;i--) if (f[m][i]) break;//可以放
	printf("%d",v-i);
	return 0;
}

JZOJ NO.3 破碎的路径

#include <iostream>
#include <algorithm>
using namespace std;
struct z{string x,y;}a[12001];
bool cmp(z u,z v){return u.y<v.y;}
int n,next[12001]; bool f[12001];
int main(){
	cin>>n;
	for (int i=1;i<=n;i++) cin>>a[i].x>>a[i].y;
	sort(a+1,a+1+n,cmp);
	for (int i=1;i<=n;i++){
		int l=1,r=n,mid; 
		while (l<=r){
			mid=(l+r)>>1;
			if (a[mid].y>a[i].x) r=mid-1; 
			else if (a[mid].y<a[i].x) l=mid+1;
			else break;
		}
		if (a[mid].y==a[i].x) next[mid]=i,f[i]=1;//查得到就赋值
	} int i;
	for (i=1;i<=n;i++) if (!f[i]) break;//没有标记说明从这个地方开始走
	for (int j=i;j;j=next[j]) cout<<a[j].x<<" "<<a[j].y<<endl;
	return 0;
}

JZOJ NO.4 无线网络

分析

其实一开始我是想用prim做的,听正解时惊呼:原来是并查集


代码

#include <cstdio>
#include <cmath>
using namespace std;
int n,d,u,v,f[1002],x[1002],y[1002]; bool use[1002]; int a[1002][1002]; 
int o(int q){return q*q;} char c;
int getf(int u){if (f[u]==u) return u; else return f[u]=getf(f[u]);}
int gett(int u,int k){if (f[u]==u) {f[u]=k;return k;} else return f[u]=gett(f[u],k);}
int main(){
	scanf("%d%d",&n,&d);
	for (int i=1;i<=n;i++){
	 scanf("%d%d",&x[i],&y[i]);f[i]=i;
	 for (int j=1;j<i;j++)  if (d>=sqrt((double)o(x[i]-x[j])+o(y[i]-y[j]))) //符合距离
	 a[i][++a[i][0]]=j,a[j][++a[j][0]]=i;//邻接表
	}
	while (scanf("\n%c %d",&c,&u)==2){
		if (c=='O'){
			use[u]=1;//可以使用
			for (int i=1;i<=a[u][0];i++)
			if (use[a[u][i]]&&f[u]==u) f[u]=getf(a[u][i]);//合并祖先
			else if (use[a[u][i]]) f[a[u][i]]=gett(a[u][i],f[u]);//合并祖先
		}
		else{
			scanf("%d",&v);
			if (!(use[u]&&use[v])) puts("FAIL");//没有修复好
			else {
				int fa=getf(u),fb=getf(v);
				if (fa==fb) puts("SUCCESS");//祖先相同
				else puts("FAIL");
			}
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值