Codeforces Round #829——无EF,以后有时间再发这个

目录

A:Technical Support

B:Kevin and Permutation

C1 :Make Nonzero Sum (easy version)

C2:Make Nonzero Sum (hard version)

D:Factorial Divisibility

E:Wish I Knew How to Sort


A:Technical Support

这里有一个小坑,就是如果只计算个数的话,QAAAQ是会被误判为对的

因为A只能回答前面出现过的所有问题

所以我们假设每个A对应一个Q,每次让Q的个数取max(0,Q-1)即可

代码实现:

#include<bits/stdc++.h>
using namespace std;
 
int main(){
	cin.tie(0),cout.tie(0);
	int t;
	cin>>t;
	while(t--){
		int n;
		cin>>n;
		string s;
		cin>>s;
		bool st;
		int op[2]={0};
		for(int i=0;i<s.length();i++){
			if(s[i]=='Q') op[0]++;
			else op[0]--,op[0]=max(0,op[0]);
		}
		if(!op[0]) puts("Yes");
		else puts("No");
	}
	return 0;
}

B:Kevin and Permutation

这里我是用找规律来写的

没有严格的证明,但是有思路可以供参考

我们假设123456这个序列和1234567这个序列

那么看题目所给样例满足2413

我们就会怀疑是否为按照大的递减前面穿插小的递减

即:6        5        4

    3        2        1        

但是如果是奇数个的话,即1234567,就是

7        6        5        4

      3        2        1

此时大的在前

所以我们分情况讨论,即分奇偶的时候,一个i在前,一个j在前

这个过程就是一个反复试验推敲的过程,非常花时间,导致我D题写出来恰好过了时间1min

也可能是我敲代码速度填慢哈哈哈

但是在这个过程中可以发现最小的间隔最大值应该是n/2

里面会出现3,4,3,4,3之类的

如果按照这个思路也会很快写出来,不过发现的时候比较晚了

具体证明可以看原题解,证明的很好,我没有严格证明,不合数学要求,就不作展示了hh

#include<bits/stdc++.h>
using namespace std;
 
int main(){
	cin.tie(0),cout.tie(0);
	int T;
	cin>>T;
	while(T--){
		int n;
		cin>>n;
		int i=n/2,j=n;
		if(n&1){
			while(i>=1||j>=(n+1)/2){
				if(j>=(n+1)/2) cout<<j--<<' ';
				if(i>=1) cout<<i--<<' ';
			}
		}else{
			while(i>=1||j>=n/2+1){
				if(i>=1) cout<<i--<<' ';
				if(j>=n/2+1) cout<<j--<<' ';
			}
		}
		cout<<'\n';
	}
	return 0;
}

C1 :Make Nonzero Sum (easy version)

无0版本

容易观察到,每次相邻二者只有两种情况:

相等,相反

比如1,1,这一段就是0;

1,-1,这一段就是2;而-1,1就是-2

但是我们可以把1,-1拆开,即单独列,此时二者又为0

这道题是一个贪心吧(自我感觉),每次使得当前状态尽量为0,所以-1和1的数组只会出现如下状态:

-1为0,1为0

-1为1,1为0或-1为0,1为1

即当二者均为1时,将二者分别单独分隔开

当二者一项为2时,将其两个两个分开

不存在一个为2一个为1,不满足第一个情况,即同时为1时没有操作

或者不满足一个为2时没有操作

代码实现:

#include<bits/stdc++.h>
using namespace std;

typedef pair<int,int>PII;

int main(){
	int T;
	cin.tie(0),cout.tie(0);
	cin>>T;
	while(T--){
		int op[3]={0};
		//0代表-1,2代表1 
		int n;
		cin>>n;
		vector<PII>v;
		for(int i=1;i<=n;i++){
			int k;
			cin>>k;
			op[k+1]++;
			if(op[0]==2||op[2]==2){
				v.push_back({i-1,i});
				op[0]=op[2]=0;
			}else if(op[0]==1&&op[2]==1){
				v.push_back({i-1,i-1});
				v.push_back({i,i});
				op[0]=op[2]=0;
			}
		}
		if(op[0]||op[2]) puts("-1");
		else{
			cout<<v.size()<<'\n';
			for(int i=0;i<v.size();i++){
				cout<<v[i].first<<' '<<v[i].second<<'\n';
			}
		}
	}
	return 0;
}

C2:Make Nonzero Sum (hard version)

原来是纸老虎

看起来很复杂

但是如果我们拆分,分类讨论

(遇事不决,分类讨论)

我们就可以发现无外乎四种情况:

1 奇数个0 1

1 偶数个0 1

1 奇数个0 -1

1 偶数个0 -1

其他的零可以不管。很显然,当非0的个数是奇数时,我们凑不出来0,故额外讨论

而当非0的个数时偶数时,就是上面这几种情况

那么我们开始针对每一种情况进行讨论,即相等时里面两个,不相等时里面两个情况

仍然选用贪心策略

别忘了要把两端之间的0给加上去

并不算难的一道题,需要不慌静下心来想想

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;

typedef pair<int,int>PII;

int main(){
	int T;
	cin.tie(0),cout.tie(0);
	cin>>T;
	while(T--){
		int n,cnt=0;
		cin>>n;
		vector<int>v;
		for(int i=0;i<n;i++){
			int k;
			cin>>k;
			v.push_back(k);
			cnt+=abs(k);
		}
		vector<PII>res;
		int i=0,j=0;
		while(j<n){
			int num=0;
			while(i<n&&!v[i]){
				num++;
				i++;
			}
			if(num) res.push_back({i-num+1,i-1+1});
			j=i+1;
			while(j<n&&!v[j]) j++;
			if(i>=n||j>=n) break;
			if(v[i]==v[j]){
				if(j-i-1&1){
					res.push_back({i+1,i+1});
					res.push_back({i+1+1,j+1});
				}else{
					res.push_back({i+1,j+1});
				}
				
			}else{
				if(j-i-1&1){
					res.push_back({i+1,j+1});
				}else{
					res.push_back({i+1,i+1});
					res.push_back({i+1+1,j+1});
				}
			}
			i=j+1;
		}
		if(cnt%2) puts("-1");
		else if(!cnt){
			cout<<1<<endl;
			cout<<1<<' '<<n<<endl;
		}else{
			cout<<res.size()<<endl;
			for(int i=0;i<res.size();i++) 
				cout<<res[i].first<<' '<<res[i].second<<endl;
		}
	}
	return 0;
}

哈哈哈我卡在这里半天原因是位运算不熟悉,我写的时候老是写j-i-1>>1&1,但这样子的话就错了,因为不需要/2的,但是大部分样例还没问题,这是个需要自己注意的细节。

D:Factorial Divisibility

阶乘和,阶乘和有什么性质吗?

好像没有,有的话可以给我说一下hhh

分解质因数什么的由于阶乘求和,而变得似乎不太可行。

观察一下样例

会发现第一个,3个2!,3个3!

3个2!就相当于3!,

加起来4个3!,即4!

即满足k*k!

则其==(k+1)!-k!

如果这么累加,那么就会出现(k+1)!-1!

而题目满足ai<x

故我们可以统计每一个数字出现的次数,然后不断进位,考虑是否能达到(k+1)!和k!

为什么不用(k+1)!-k!呢?

因为难以保证每个点恰好为k*k!

代码实现:

#include<bits/stdc++.h>
using namespace std;

const int N=5e5+10;
int num[N];

int main(){
	int n,x;
	cin>>n>>x;
	for(int i=0;i<n;i++){
		int k;
		cin>>k;
		num[k]++;
		num[k+1]+=num[k]/(k+1);
		num[k]%=(k+1);
	}
	for(int k=1;k<n;k++){
		num[k+1]+=num[k]/(k+1);
		num[k]%=(k+1);
	}
	for(int i=0;i<x;i++){
		if(num[i]!=0){
			puts("No");
			return 0;
		}
	}
	puts("Yes");
	return 0;
}

由于必定存在,我们考虑到x-1这个位置

当后面出现不为0的时候,必然无法被整除

而num[x]和num[x+1]的位置

谁在乎,没必要判断,多少都能被整除了。

E:Wish I Knew How to Sort

这个是个概率题,虽然题解给的是dp,但是知乎大佬cup-pyy写的是纯概率

写的很简单通俗,

但对我来说,目前我的重点不在这里,所以先放放,感兴趣的可以自行搜索那位大佬的

F:

目前来说这个难度不适合我,等我先把cf的分稳定到附近再说

  • 13
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值