NEUQ2020训练赛1总结(cf ECR 34)

比赛地址.

A. Hungry Student Problem

题意:100以内,判断是否可以由若干个3和7组成

#include<iostream>
#define rep(i,x,y) if((x)<=(y))for(register int i=(x);i<=(y);i++)
#define TT() int t;cin>>t;while(t--) 
using namespace std;
bool f[200];
void solve(){
	int n;cin>>n;
	if(f[n])cout<<"YES"<<endl;
	else cout<<"NO"<<endl;
} 
int main(){
	std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	f[0]=1;
	rep(i,1,105){
		if(f[i-3]||f[i-7])f[i]=1;
	}
	TT(){
		solve();
	}
	return 0;
}

B. The Modcrab

题意:某人打怪物,生命值h1,每轮攻击力a1,每次补给生命值增加c1(可补给无限次),怪物生命值h2,每轮攻击力a2。
每轮这个人可以选择攻击或者补给,然后接受怪兽攻击。题目保证这个人最终会赢。
思路:模拟,

#include<iostream>
#define rep(i,x,y) if((x)<=(y))for(register int i=(x);i<=(y);i++)
using namespace std;
int h1,a1,c1,h2,a2;
bool f[100010];
void solve(){
	cin>>h1>>a1>>c1>>h2>>a2;
	int ans=0;
	while(h2>0){
		if(h1>a2||h2<=a1)h2-=a1,f[ans++]=0;//这轮不会死或者会击败对方 就攻击 
		else h1+=c1,f[ans++]=1;//否则本轮补给 
		h1-=a2;//模拟 
	}
	cout<<ans<<endl;
	rep(i,0,ans-1){
		if(f[i])cout<<"HEAL"<<endl;
		else cout<<"STRIKE"<<endl;
	}
} 
int main(){
	std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	solve();
	return 0;
}

C. Boxes Packing

题意:n个正方体盒子,小盒子可以放到大盒子里面,问最终能看到的(外面的)盒子有多少个?
思路:显然大小严格递增的盒子可以放在一起,那么问题就转化成了求同样大小的盒子最多有多少个。使用map来解决。

#include<iostream>
#include<map> 
#define rep2(i, x) for(register int i = h[x]; i; i = e[i].nxt)
#define rep(i,x,y) if((x)<=(y))for(register int i=(x);i<=(y);i++)
#define endl "\n" 
using namespace std;
map<int,int> mp;
void solve(){
	int n,x;cin>>n;
	rep(i,1,n){
		cin>>x;
		if(mp[x])mp[x]++;
		else mp[x]=1;
	}
	int ans=1;
	for(map<int,int>::iterator it=mp.begin();it!=mp.end();it++){
		ans=max(ans,it->second);
	}
	cout<<ans<<endl;
} 
int main(){
	std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	solve(); 
	return 0;
}

D. Almost Difference

题意:n个数组成的数组a,对于任意的i<j,求和d(a[i],a[j])。
思路:函数d只是在差<=1的时候有特例,就可以把问题分为两部分,求 (1) 所有a[j]-a[i](i<j)的和(可以用(i-1)*x-sum累积求出,sum是前面的数的和)和 (2) 求当前数与前面所有值为(当前数-1)、(当前数+1,)产生的d()的和,然后两者相减。
需要注意的是这个题的结果会很大,需要使用long double,而且输出使用printf("%.0Lf",cnt)。

#include<iostream>
#include<map> 
#define rep(i,x,y) if((x)<=(y))for(register int i=(x);i<=(y);i++)
#define endl "\n" 
using namespace std;
map<int,int> mp;
long double sum,cnt,x;
void solve(){
	int n;cin>>n;	
	rep(i,1,n){
		cin>>x;
		cnt+=(i-1)*x-sum;
		cnt-=mp[(int)x-1];
		cnt+=mp[(int)x+1];
		sum+=x;
		mp[(int)x]++;
	}
	printf("%.0Lf",cnt);
} 
int main(){
	std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	solve();
	return 0;
}

E. Swapping Characters

题意:现在有这样一个过程:把字符串s赋值k份,然后每一个字符串交换其中两个(一对)字符(字符可以相同,但是下标不可以)。
现在题目给出k个字符串,让你判断这k个字符串是否可以由一个字符串s按上述过程得来,如果可以,输出这个字符串,如果不可以,输出-1。
思路:首先任意两个串的字符出现情况要相同;
已知某串与基准字符串的(汉明距离为2)或者(汉明距离为1且该串存在某个字符至少出现两次),可以通过一次变换到基准字符串。
现以第一个串为基准先计算它与其他字符串初始的汉明距离。
然后暴力枚举第一个字符串中交换的两个字符,计算交换后的与每个其他字符串的新的汉明距离,如果新的汉明距离全部符合要求就是我们要的答案了。

#include<iostream>
#include<map> 
#define rep(i,x,y) if((x)<=(y))for(register int i=(x);i<=(y);i++)
#define endl "\n" 
using namespace std;
string s[2510];
map<char,int> mp[2510];//统计每个串的字符出现情况 
int hm[2510];
bool have2[2510];
void solve(){
	int k,n;cin>>k>>n;
	rep(i,0,k-1){
		cin>>s[i];
		rep(j,0,n-1){
			char c=s[i][j];
			if(mp[i][c])have2[i]=1;
			mp[i][c]++;
		}
	}
	bool f=1;
	rep(i,0,k-1){
		rep(j,i+1,k-1){
			if(mp[i]!=mp[j]){
				f=0;break;//只要有两个字符串的字符组成不相同就一定不行 
			}
		}
		if(!f)break;
	}
	if(!f){
		cout<<-1;return;
	}
	rep(i,1,k-1){
		rep(j,0,n-1){
			if(s[i][j]!=s[0][j])hm[i]++;//计算第一个字符串与其他所有字符串的汉明距离 
		}
	} 
	int ansi,ansj;
	rep(i,0,n-1){
		rep(j,i+1,n-1){//暴力枚举第一个字符串的交换情况 
			f=1;
			rep(q,1,k-1){//重新计算现在一个字符串与其他所有字符串的汉明距离 
				int now=hm[q];
				if(s[0][i]!=s[q][i]) now--;
				if(s[0][j]!=s[q][j]) now--;
				if(s[0][i]!=s[q][j]) now++;
				if(s[0][j]!=s[q][i]) now++;
				if(now>2||(!have2[q]&&now==0)){
					f=0;break;
				}
			} 
			if(f){
				ansi=i,ansj=j;break;
			}
		}if(f)break;
	} 
	if(!f)cout<<-1;
	else {
		swap(s[0][ansi],s[0][ansj]);
		cout<<s[0];
	}
} 
int main(){
	std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	solve(); 
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值