codeforce刷题② 交互题

打codeforces第二周

又遇到了很多有意思的题型,可自己还是太菜了

写份博客记录一下憨憨的自己

做的第一道交互题,记录一下

1.1407C Chocolate Bunny(交互题+双指针)

题目链接:https://codeforces.com/contest/1407/problem/C

This is an interactive problem. 这是一道交互题

你通过打印问题询问他,他给你结果,让你找到最终的数组

需要清除缓存区,才能保证正确,否则就会Idleness limit exceeded(我第一次见这种错误,因为没读清楚题,一直在第1个测试点报这个错误www...还是做题太少了)

我把所有的printf换成cout就ac了或者每次输出后都加一句cout.flush()fflush(stdout)

题目大意

样例解释:给你n=3,说明让你得到的数组中只包括1,2,3三个元素,让你找到最终顺序。

根据结果:他找到的最终顺序是 1 3 2

你可以通过询问来查找,? 1 2 就是询问你第一个位置的数%第二个位置数得到的值,在输入框中给答案 1 。即1%3 -> 1。

解题思路

每当比较两个位置的数 a , b 的时候,进行两次 a % b 和 b % a就一定可以得出那个小的数。 1 % 3 = 1 ,

3 % 1 = 0,所以找那个稍微大的数,就是准确的值。

所以,可以运用双指针,第一个指针指向左边那个未得到答案的位置,第二个指针一直向后移动,到最后只有一个值没有得到,再寻找一遍谁未赋值再赋值就可以了。

AC代码

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 1e4+4;
int ans[maxn];
bool vis[maxn];
int main(){
	int n;
	scanf("%d",&n);
	int x=1;
	int s,c;
	for(int i=2;i<=n;i++){
		cout<<"? "<<x<<' '<<i<<endl;
		cin>>s;
		cout<<"? "<<i<<' '<<x<<endl;
		cin>>c;
		if(s<c){
			ans[i]=c;
			vis[c]=true;
		}else{
			ans[x]=s;
			vis[s]=true;
			x=i;
		}
	}
	int xx;
	for(int i=1;i<=n;i++){
		if(!vis[i]){
			xx=i;
			break;
		} 
	} 
	cout<<"!";
	for(int i=1;i<=n;i++){
		if(ans[i]==0){
			ans[i]=xx;
		}
		cout<<' '<<ans[i];
	}
	return 0;
}

2.1417 C. k-Amazing Numbers ( 思 维 )

这道题的思维真的很奇特~。

大致题意

t = 3

给n = 5(数组中有5个数)分别是 1 2 3 4 5

结果是:第一个数:所有的包含一个数的子数组共同包含的最小的数(没有则输出-1)

​ 第二个数:所有包含两个数的子数组共同包含的最小的数

​ .......

解题思路

遍历一遍数组找到每个数距离相邻同元素最远的距离(相当于最多差几个数能找到第二个它)

左右两边也要处理。

AC代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 3e5+5;
int a[N];
int d[N];//用来存当前位置
int f[N];//用来存每个数相邻的最小间距
int x[N];//用来存每个位置的最小值(输出答案时使用)
int main(){
	int t;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		memset(x,0x3f,sizeof x);
		memset(f,0,sizeof f);
		memset(d,0,sizeof d);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);	
		}
		for(int i=1;i<=n;i++){
			f[a[i]]=max(f[a[i]],i-d[a[i]]);
			d[a[i]]=i;
		}
		for(int i=1;i<=n;i++){
			if(f[i]!=0){
				f[i]=max(f[i],n+1-d[i]);
				x[f[i]]=min(x[f[i]],i);
			}
		}
		int xx=0x3f3f3f3f;
		for(int i=1;i<=n;i++){
			if(x[i]!=0x3f3f3f3f){
				xx=min(x[i],xx);
			}
			if(xx!=0x3f3f3f3f){
				cout<<xx<<' ';
			}else{
				cout<<"-1 ";
			}
		}
		cout<<endl;
	}
	return 0;
} 

3.1443 B. Saving the City(贪心)

题目大意

有很多城市,城市下面可能有炸弹,1表示有炸弹,0表示没有。

为了拆除所有的炸弹,有两种方法。

第一种:引爆炸弹 其引爆的n+1和n-1的位置的炸弹也会被引爆。

第二种:放新的炸弹,和原来炸弹合并在一起,用其他的炸弹的引爆来引爆它。

解题思路

排除一个炸弹的时候一定是通过引爆的形式排除的。排除后面的可以选择引爆或者与前面的连接。这时候贪心即可,看哪个便宜,选哪个。

AC代码

#include <iostream>
#include <string>
using namespace std;
int main(){
	int t;
	cin>>t;
	while(t--){
		int a,b;
		string x;
		cin>>a>>b>>x;//个数>b/a+1的时候 选a+b 否则n*a
		int len=x.size();
		bool flag=false;
		int ans=0;
		int num=0;
		for(int i=0;i<len;i++){
			if(x[i]=='1'&&!flag){
				flag=true;
				ans+=a;
				num=0;
			}else{
				if(x[i]=='0'){
					num++;
				}
				else{
					if(num)
						ans+=min(a,num*b);
					num=0;
				}
			}
		
		}
		cout<<ans<<endl;
													
	}
	return 0;
}
原文地址:https://www.cnblogs.com/AC673523745/p/13939882.html