Codeforces Round #837 A~C题解

Codeforces Round #837 A~C题解

补题链接
前排提示:一些个人废话,想看题解直接往下看。
因为要打杭州打星,昨天才终于到家,十一点到,吃了口饭,赶紧上号cf,想着上一波分,但是结果不尽人意。A题第一发WA了,想到需要特判数组数值相同的情况,结果把组合数 A n 2 A_{n}^2 An2直接当成了 n ! n! n!。WA了好几发才发现。B题,思维题,第一遍忘记考虑了后续点对前面点的影响,想到之后,没想好怎么样去更新。直接用*min_element()超时了,时间来不及,最后遗憾掉分。

A Hossam and Combinatorics 思维
题意:给你一组数,求出满足两数差的绝对值等于该数组的极差的对数。
思路:直接统计最小值和最大值数量,然后相乘再乘2即可。注意!特判最大值和最小值相同的情况。这时候数组中所有元素值相同,所以对数的结果就是 A n 2 = n ∗ ( n − 1 ) A_{n}^2=n*(n-1) An2=n(n1)。注意开long long。
代码:

void solve(){
	LL n;
	cin>>n;
	for(int i=0;i<n;i++) cin>>a[i];
	LL minn=*min_element(a,a+n);//求出最小值
	LL maxn=*max_element(a,a+n);//求出最大值
	LL n1=count(a,a+n,minn);//统计最小值数量
	LL n2=count(a,a+n,maxn);//统计最大值数量
	//特判 数组中元素全部相同的情况
	if(minn==maxn) cout<<LL(n*(n-1))<<endl;
    else cout<<LL(n1*n2*2)<<endl;
	return;
}

B. Hossam and Friends 思维
题意:给你一个数n,表示有1~n个数。 给你m个限制,每个限制给出a和b,说明a和b不能同时出现。求出满足[ a i , a j a_{i},a_{j} ai,aj]的数量。
思路:对于每组限制的输入,我们用一个数组来存,如果一个结点存在多组情况,比如1 2和1 3。根据题意,1 2的情况包含了1 3的情况。所以多组情况,我们维护最小值即可。对于每组限制b[i],对答案的贡献为b[i]-i。这里还需注意!后续的情况是会对前面的情况有影响的。比如1的限制最小的情况是4, 2的最小限制3,那么本来1的情况可以取[1],[1,2],[1,2,3]。但由于2的限制是3。所以1的情况只能[1],[1,2]。等价于1的限制缩小到了2的限制,也就是3。这样我们就需要维护一个后缀最小值。
代码:

void solve(){
	LL n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++) b[i]=n+1;//初始化
	while(m--){
		int x,y;
		cin>>x>>y;
		if(x>y) swap(x,y);//限制统一小的在前
		b[x]=min(b[x],y);
	}
	for(int i=n-1;i>0;i--){//维护后缀最小值
		b[i]=min(b[i],b[i+1]);
	}
	LL ans=n*(n+1)/2;
	for(int i=1;i<n;i++){
        ans-=(n-b[i]+1);
	}
	cout<<ans<<endl;
	return;
}

C. Hossam and Trainees 数学+质因数分解
题意:给你n个数,判断n个数中是否有两个数的最大公约数大于1.
思路;我们对每个数进行质因数分解,如果n个数中存在了相同的质因数,那么说明满足情况。因为数据范围是1e9,质因数分解的复杂度是O( n \sqrt{n} n )。所以我们可以提前预处理所有的素数。有一个结论,前n个数中有 n ln ⁡ n \frac{n}{\ln{n}} lnnn。所以本题的质数不超过40000个,可以通过。
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e5+10int a[N];
vector<int> prime;
bool st[N];
void get_primes(int n){//筛素数
  for(int i=2;i<=n;i++){
	if(!st[i]) prime.pb(i);
	for(int j=0;prime[j]<=n/i;j++){
		st[prime[j]*i]=true;
		if(i%prime[j]==0) break;
	}
  }
}
void solve(){
	int n;
	cin>>n;
	map<int,int> mp;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++){
       int num=a[i];
	   for(int p:prime){
		if(p*p>num) break;
		if(num%p==0){
			while(num%p==0) num/=p;
            mp[p]++;
			if(mp[p]>=2){
				cout<<"YES"<<endl;
				return;
			}
		}
	   }
	   if(num>1) mp[num]++;
	   if(mp[num]>=2){
		cout<<"YES"<<endl;
		return;
	   }
	}
	cout<<"NO"<<endl;
	return;
}
int main()
{
	get_primes(40000);
      int T;
      cin>>T;
      while(T--){
      solve();
    }
    return 0;
}
  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Showball.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值