Codeforces#808(Div.2)A-D题解

目录

A. Difference Operations

B. Difference of GCDs

C. Doremy's IQ

D. Difference Array


A. Difference Operations

Problem - A - Codeforces

 题意:给一串长度为n的数,对于下标 i 范围 [2,n] ,可以执行a[i]=a[i]-a[i-1]的操作,操作次数不限,问能否可以变成第2~n位都是0.

思路:其实就是要后面每个数都得是第一个数的倍数就行了。【亏我之前还分析了那么久,一开始以为要递增,但可以递减,但必须满足第二个数大于等于第一个数啥啥啥的,还wa了几发...后面才推出这个关系,(不然是消不干净的】

这代码也要贴嘛?算了贴一下吧,毕竟我个菜鸡折腾了那么久qwq

#include<iostream>
using namespace std;
int n,a[110];
void solve(){
	cin>>n;
	int f=0;
	cin>>a[1];
	
	for(int i=2;i<=n;i++){
		cin>>a[i];
		if(a[i]%a[1])f=1;
	}
	cout<<(f?"NO\n":"YES\n");	
	
}
int main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int t;cin>>t;
	while(t--)solve();
	return 0;
}

B. Difference of GCDs

Problem - B - Codeforces

 题意:给你三个数 n, l , r,问你能不能构造一个长度为 n 的数组并且数组元素大小要在 [ l , r ]之间,使得数组元素与对应下标的最大公因数各不相同,如果能就YES输出任意一种,不然输出NO

分析:其实很容易就看出来各组的最大公因数就是下标本身(因为下标就是从1开始递增,最大公因数又不能超过它,又要求各不相同,那不就是下标了)然后就是看能不能在 [ l, r ] 区间内找到该下标的倍数惹~ 我当时推的公式是  tp=l+i-l%i ,然而刚发现如果恰好 l 是 i 倍数的情况没考虑。。所以是这样才对:

int tp;
if(l%i)tp=l+i-l%i;
else tp=l;
if(tp<=r)ans[++ct]=tp;

但是我wa的主要原因还是在于。。多了个特判n<=r-l+1。因为可以重复取同一个数嘛,就没必要这个条件了(错了傻傻不知道的我www)然后是jj告诉我这个错误的,她的公式就很棒啊:tp=r/i*i;

#include<iostream>
using namespace std;
typedef long long ll;
const int M=1e5+6;
ll n,l,r,ans[M];
void solve(){
	cin>>n>>l>>r;
	//if(n>r-l+1){cout<<"NO\n";return;}这句别要,因为可以重复用一个数哇www 
	for(int i=0;i<=n;i++)ans[i]=0;
	int ct=0;
	for(int i=1;i<=n;i++){
		ll tp=r/i*i;
		if(tp>=l&&tp<=r)ans[++ct]=tp;
		else{cout<<"NO\n";return;}
	}
	cout<<"YES\n";
	for(int i=1;i<=ct;i++)cout<<ans[i]<<' ';
	cout<<'\n';
}
int main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int t;cin>>t;
	while(t--)solve();
	return 0;
}

以上为比赛时 过了的俩,后面CD是补题(当时C真不觉得自己错了的。。后面jj一讲。错误百出)

总之学姐说的太对了,1.我的出题速度太慢了,得多做思维题才行(cf前面的题基本就只是思维都没啥算法)2.然后要学会“跟榜”,很多人都能过的,我的又过了样例的,那基本就得看看开long long 没了,(然后很少会因为 long long 卡时间,所以多开点 long long 没关系)3.要多自己debug,知道自己错哪些地方,输出中间变量啥的(其实我有啊www)plus:思维,会思考,是   OIer 亦或是 Acmer 最重要、最基本的要求。


C. Doremy's IQ

Problem - C - Codeforces

 题意:某人被要求测试n场比赛,给出比赛难度与此人初始IQ, 若比赛难度大于此时IQIQ值就会减一,否则IQ值无变化,IQ值必须大于0时才能进行测试,问最多能测试几个。

分析:(方括号内的 菜鸡错误过程 可忽略,直接看后面黑体即可)

【我一开始就想着,最后 q ( IQ 值)场肯定能测,然后前面的要是难度不大于 q 就可以.....感觉有点像是倒推的想法了,但是(肯定)过不了。。后面jj跟我讲我思路的问题:后面几场可能不大于IQ值啊,我的太“静态”了。方才听到pbrjj 真正的倒推思路:设一个值,从后往前,碰到大于的就加一,直到与IQ相等(!)然后第二天一早我就去敲,调了半天过不了。。拜谢学姐再次出马教与我倒推,我的“倒推”极不“标准”我的tp值是从1开始的...就当作进入测试的时候的IQ值啥的,而且每次都是与题给的初始IQ值比较...】所以应该从最后的0开始,与当前的tp值比较大小,一路往前推直至tp==q(IQ值已拉满了)

#include<iostream>
#include<algorithm>
using namespace std;
 const int M=1e5+6;
int n,q,a[M],f[M];
void solve(){
	cin>>n>>q;
	for(int i=1;i<=n;i++)f[i]=0;
	for(int i=1;i<=n;i++)cin>>a[i];
	int tp=0;
	for(int i=n;i;i--){
		if(a[i]<=tp)f[i]=1;
		if(a[i]>tp&&tp<q)tp++,f[i]=1;
	} 
	for(int i=1;i<=n;i++)cout<<f[i];
	cout<<'\n';
}
int main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int t;cin>>t;
	while(t--)solve();
	return 0;
}

jj是用二分写的,看题解也看到了二分的方法(真的好多题目都可以用二分啊  可惜我个fw不熟悉,害怕二分www)在这里贴一下: 算了刚看了下没看懂。。。学二分学二分www

D. Difference Array

Problem - D - Codeforces

 题意:给你一个长为n的数组 a,然后你得到它的差分数组 b ,把 b 从小到大排序,再算它的差分数组......重复此过程直至只剩一个数,输出这个数。

分析:0的数量会爆增...( ! ) 所以按学长的话就是直接模拟就能过,维护好数组,不要把0放进去。=.=然后看题解,看到用map的,还用了lambda表达式(又叫“匿名函数”)看懂后我直呼妙哉好吧。。关于lambda表达式,之前见过(学长代码里)(学长还发了他写的博客,但写得太高级了窝没看懂qwq)这里有篇通俗易懂的:C++Lambda表达式,超详细的讲解,保证一遍懂_Zjkai_的博客-CSDN博客_c++ lambda

奉上代码:

#include<iostream>
#include<map>
using namespace std;
int n;
void solve(){
	cin>>n;
	map<int,int> mp;
	auto work=[&](){//lambda表达式 
		map<int,int> mp1;
		for(auto it = mp.begin(); it != mp.end(); it++){
			if(it->second > 1)mp1[0]+=it->second -1;
			auto it1 = it; it1++;
			if(it1 != mp.end())mp1[it1->first - it->first]++;
		}
		mp=mp1;
	};//lambda表达式结尾要分号... 
	for(int i=1,x;i<=n;i++)cin>>x,mp[x]++;
	for(int i=1;i<n;i++)work();
	cout<<mp.begin()->first<<'\n';
}
int main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int t;cin>>t;
	while(t--)solve();
	return 0;
}

没错我还是看到了二分的大佬题解,原文片段如下

2 5 8 10 13 17 22 28 -- 差分 --> 3 3 2 3 4 5 6 -- sort --> 2 3 3 3 4 5 6 
2 3 3 3 4 5 6 -- 差分 --> 1 0 0 0 1 1 1 -- sort --> 0 0 0 1 1 1 1
0 0 1 0 0 0 -- 差分 --> 0 0 0 0 1 此时已经发现结果最后必然是1了。  n为8但是我们只差分了3次

我们发现0的数量是会突然巨增的(多造几组样例试试),如何减少时间复杂度呢?忽略大量的0即可,我们只需要找到第一个非0的位置,在这个位置之后进行差分即可。每一次去模拟这个过程,所有位置要先左移一格,因为a[1]会不断删去,然后直接暴力遍历找非0位置,也可以二分(时间复杂度都允许,因为0的出现非常的多),记录非0位置,从这个位置开始往后做差分,若非0位置的数只剩一个了那么就可以停止循环。其实他的时间复杂度是远低于n^2logn的。

注意在做差分的时候其实找的是最后一个0,因为这个0对后面的差分仍然具有贡献,看上面模拟的样例,这道题的边界问题比较复杂,我注释写的比较详细了。

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
#define NO {puts("NO") ; return ;}
#define YES {puts("YES") ; return ;}
const int N = 2e5 + 10 , INF = 0x3f3f3f3f;
int n, m, a[N], p;

void solve()
{
    cin >> n;
    for(int i = 1 ; i <= n ; i ++ ) cin >> a[i];
    for(int i = 1 ; i <= n ; i ++ )
        if(a[i]) {p = i - 1; break;} // 找末尾0
        
    while(n > 1) // 循环结束的条件是n的长度为1
    {
        for(int i = max(1, p) ; i <= n - 1 ; i ++ ) // 从p到n做差分
            a[i] = a[i + 1] - a[i];  // 注意p不能是0,最少是1,假如没有0的话p算出来就是0,出界了
        n -- ; // n 缩小
        sort(a + p , a + n + 1); // 排序
        // 二分找末尾0
        int l = 0, r = n;
        while(l < r)
        {
            int mid = l + r + 1 >> 1;
            if(a[mid]) r = mid - 1;
            else l = mid;
        }
        p = l;
        if(l + 1 == n) break; // l+1是第一个非0位置,如果第一个非0是n那么说明只有一个数非0,直接退出循环即可。
    }
    cout << a[n] << endl;
}

int main()
{
    int T;
    cin >> T;
    while(T -- ) solve();
    return 0;
}

!!!太菜了www我要去学二分www(然鹅dp折腾快两周了还是没学明白。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值