2020年ICPC南京站铜牌题练习

K Co-prime Permutation

题意:
给定n,k,要求构造一个1~n的排列a,
满足存在恰好k对:
gcd(a[i],i)=1.
如果无解输出-1.
数据范围:n<=1e6

思路:
这题具有一定迷惑性,我们看到肯定会想到质数和别的数的gcd是1,但是这样的话我们就相对于难一点去构造了,其实我们会发现,x和x+1的gcd一定是1,所以我们只需让x在x+1的位置上,然后头尾对调一下。以上操作对前k个数进行,保持后n-k个数不变,这样我们就能很简单的构造出来了。当然因为因为无论如何都有一个1的位置使得gcd==1,所以k=0的情况就不成立了。

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int N=1e6;
int a[N];
int n,k;
signed main()
{
	IOS;
	cin>>n>>k;
	if(k==0) cout<<"-1";
	else
	{
		for(int i=1;i<=k;i++)
		{
			if(i!=k) cout<<(i+1);
			else cout<<1;
			cout<<" ";
		}
		for(int i=k+1;i<=n;i++)
		{
			cout<<i<<" ";
		}
	}
	return 0;
}

L Let’s Play Curling

题意:
红石头属于红队,蓝石头属于蓝队,分别给出所有红色蓝色石头在数轴上的位置,构造目标点的位置(实数),使得红队胜利且获得的分数尽可能多,红队的分数 等于 所有 比所有蓝石头离目标点近 的红石头 的数量,求 红队的最大分数或者如果无法赢就输出impossivle

思路:
说实话这题没转过来,参考题解后发现两个蓝色石头中间红色石头数量就是得分数(取max)
因为在两个蓝色石头之间的红色石头一定比所有蓝色石头更近c,且蓝色石头外的红色石头不满足比所有蓝色石头更近,因此,证为最优解

一道奇怪的贪心题剩下的我们直接二分找一下位置就好了,时间复杂度肯定能过的。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
int a[maxn],b[maxn];
int t,n,m;
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		for(int i=1; i<=n; i++) scanf("%d",&a[i]);
		for(int i=1; i<=m; i++) scanf("%d",&b[i]);
		sort(a+1,a+1+n);
		sort(b+1,b+1+m);
		//注意不要漏了0和最大值这两个边界
		b[0]=0;
		b[m+1]=1000000001;
		int maxx=0;
		for(int i=0; i<=m; i++){
			int l=b[i], r=b[i+1];
			//注意下标从1开始
			int len=lower_bound(a+1,a+1+n,r)-1-upper_bound(a+1,a+1+n,l)+1;
			maxx=max(maxx,len);
//			printf("%d %d %d\n",x,y,maxx);
		}
		if(maxx==0) puts("Impossible");
		else printf("%d\n",maxx);
	}
	return 0;
}

F Fireworks

题意:
你每做一个烟花要n分钟,释放已做好的所有烟花需要m分钟,每只烟花成功释放的概率为p。问你在采取最优策略的前提下,直到成功释放第一个烟花时最小的期望时间花费。

思路:
我们可以设每制作k个烟花后集中释放一次。这个问题可以转化为每次制作并释放k个烟花,重复这一过程直到某次释放时成功出现一个烟花为止,求当前期望时间花费。这就变成了一个典型的几何分布问题。
每次开销kn+m,我们成功释放一个烟花的概率为(1-(1-p)^k),根据几何概型得到期望是1 / (1-(1-p)^k),然后我们就可以得到开销(kn+m) / (1-(1-p)^k)。

通过求二阶导后我们可以得到这是一个凹函数(过程太多,很难展示),求min,那我们就利用三分搞定他。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
ll n,m,p;
int t;
double px;
double fun(ll x){
	return (n*x+m)*1.0/(1.0-pow(1.0-px,x));
}
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%lld%lld%lld",&n,&m,&p);
		px=p*0.0001;
		ll l=1,r=0x3f3f3f3f;
		while(l < r - 1) //三分求凹函数极值
    	{
	        ll mid = (l + r) / 2;
	        ll mmid = (mid + r) / 2;
	        if(fun(mid) > fun(mmid)) l = mid;
	        else r = mmid;
    	}
    	int ans;
    	if(fun(l)<fun(r)) ans=l;
    	else ans=r;
//    	cout << ans << endl;
     	printf("%.10f\n",fun(ans));
	}
	return 0;
}

E Evil Coordinate

题意:
在一个图中,一个人从(0,0)进行上下左右行走。有一个地雷点(mx,my)。询问可不可以通过改变行走上下左右的顺序(不改变上下左右走的次数),可以避开雷。如果有多个,输出任意一种,如果没有,输出Impossible!

思路:
这题我一开始的分类情况可能是漏了,所以导致我WA了,而且hack样例也很难想,然后参考了一下题解。
其实我们要懂一个原则:
不管我们如何全排列给的字符串,我们最后都能走到终点,所以我们可以贪心UDLR每个都一次走完,然后我们全排列UDLR这个序列,在走的过程中判断是否会踩到地雷,最后我们要知道如果雷在起点和终点我们是必走不了的。

#include <bits/stdc++.h>
using namespace std;
int t,mx,my;
int stx,sty,edx,edy;
int a[4]={0,1,2,3};
int cnt[4];
int op[4][2]={0,1,0,-1,-1,0,1,0};//注意这里一定要一一对应 
unordered_map<int,char> mp;
string s;
bool check(){//模拟全排列走一遍,边走边判断是否出现了踩到地雷的情况。 
	int x=0,y=0;
	for(int i=0; i<4; i++){
		for(int j=0; j<cnt[a[i]]; j++){
			x+=op[a[i]][0];
			y+=op[a[i]][1];
			if(x==mx&&y==my) return false;
		}
	}
	return true;
}
int main(){
	scanf("%d",&t);
	while(t--){
		memset(cnt,0,sizeof cnt);
		scanf("%d%d",&mx,&my);
		cin >> s;
		a[0]=0,a[1]=1,a[2]=2,a[3]=3;
		mp[0]='U',mp[1]='D',mp[2]='L',mp[3]='R';
		edx=0,edy=0,stx=0,sty=0;
		for(int i=0; i<s.size(); i++){
			if(s[i]=='U'){
				edy++;
				cnt[0]++;
			}
			else if(s[i]=='D'){
				edy--;
				cnt[1]++;
			}
			else if(s[i]=='L'){
				edx--;
				cnt[2]++;
			}
			else if(s[i]=='R'){
				edx++;
				cnt[3]++;
			}
		}
		if((edx==mx&&edy==my)||(stx==mx&&sty==my)){
			puts("Impossible");
			continue;
		}
		int flag=0;
		do{//全排列 
			if(check()){
			//有一组可行解那就可以输出了
				flag=1;
				for(int i=0; i<4; i++){
					for(int j=0; j<cnt[a[i]]; j++){
						printf("%c",mp[a[i]]);
					}
				}
				puts("");
				break;
			}
		}while(next_permutation(a,a+4));
		if(!flag) puts("Impossible");
	}
	return 0;
}

总结:这站的铜牌题考了个三分算法+概率论,其他都是思维题了,所以铜牌题的注重思维题,然后我们也得注重一下数论,其他算法的知识考得是比较浅的。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值