开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第18天,点击查看活动详情
【Codeforces】Codeforces Round #837 (Div. 2) A-C 解题记录
比赛链接
Dashboard - Codeforces Round #837 (Div. 2) - Codeforces
A. Hossam and Combinatorics
题目大意
给定长度为 的数组 ,求有多少个二元组 满足:
。
思路
如果所有的数都相等,那么答案就是 。
否则,答案是所有等于最小值的数量与最大值的数量之积的两倍。
代码
#include <stdio.h>
#include <algorithm>
using namespace std;
using LL=long long;
const int N=1e6+5;
int n,m,k;
int a[N];
LL solve()
{
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",&a[i]);
LL cnt1,cnt2;
cnt1=cnt2=0;
sort(a+1,a+1+n);
if (a[1]==a[n]) return 1ll*n*(n-1);
for (int i=1;i<=n;++i)
{
cnt1+=(a[i]==a[1]);
cnt2+=(a[i]==a[n]);
}
return cnt1*cnt2*2;
}
int main()
{
int T=1;
scanf("%d",&T);
while (T--) printf("%lld\n",solve());
return 0;
}
B. Hossam and Friends
题目大意
有 个人, 个关系。其中第 个关系 表示 和 不是朋友。除了题目中说明的 对人不是朋友之外,其他人两两之间都是朋友。
求有多少个区间 ,满足从第 个人到第 个人,这 个人两两都是朋友。
思路
我们从 到 枚举 ,对每个 的取值分别求有多少个合法的 。
有多少个合法的 应该怎么求呢?
合法的区间显然不能跨越任何一对给定的 ,所以对于第 个关系式,如果 ,那么合法的 不能小于 。当我们得到了 可以取的最小值 ,那么右端点是 的合法区间就有 个
但是如果枚举输入的关系来求 可以取的最小值,时间复杂度是 ,考虑优化。
我们先对所有的关系按 的值从小到大排序,将其放入队列中。一直维护一个 表示 最小的合法取值,最初 。每枚举一个新的 ,我们都用如下方式试图对 进行更新:
- 如果队列为空,则退出更新流程。
- 令 表示队首元素,即 表示队首元素的 值。
- 如果 ,则说明 不应小于 ,更新 ,队首元素出队,跳转到步骤 1。
- 退出更新流程。
通过上述方式,我们保证了所有 值不超过 的关系都对 的合法范围进行了更新。同时,每个 可能的取值我们只会进行一次失败的比较,每个关系只会出队一次,所以时间复杂度为 。
代码
#include <stdio.h>
#include <algorithm>
using namespace std;
using LL=long long;
const int N=1e6+5;
struct asdf{
int l,r;
bool operator < (const asdf a) const
{
return r<a.r;
}
}a[N];
int n,m,k;
LL solve()
{
scanf("%d",&n);
scanf("%d",&m);
for (int i=1;i<=m;++i)
if (scanf("%d%d",&a[i].l,&a[i].r),a[i].l>a[i].r)
swap(a[i].l,a[i].r);
sort(a+1,a+1+m);
LL ans=0;
for (int i=1,j=1,l=1;i<=n;++i)
{
while (j<=m&&a[j].r<=i) l=max(l,a[j++].l+1);
ans+=i-l+1;
}
return ans;
}
int main()
{
int T=1;
scanf("%d",&T);
while (T--) printf("%lld\n",solve());
return 0;
}
题目大意
给定 个正整数 ,判断是否存在二元组 满足:
- 。
- 。
- 。
数据范围如下图所示。
思路
把 范围内的质数筛出来,共有 个。
遍历 ,对 进行质因数分解,将 的质因数去重后加入到 数组里。
如果 数组中有重复的数字出现,即可输出 YES
。
时间复杂度为
代码
#include <stdio.h>
#include <algorithm>
#include <math.h>
using namespace std;
using LL=long long;
const int N=1e6+5;
const int MAXX=31622;
int v[MAXX],p[MAXX],tot;
int a[N],b[N*15];
int n,m,k;
LL solve()
{
tot=0;
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",&a[i]);
for (int i=1,flag;i<=n;++i)
{
flag=1;
for (int j=1;j<=m&&p[j]*p[j]<=a[i];++j)
{
if (a[i]%p[j]!=0) continue;
while (a[i]%p[j]==0) a[i]/=p[j];
b[++tot]=p[j];
}
if (a[i]!=1) b[++tot]=a[i];
}
sort(b+1,b+1+tot);
for (int i=2;i<=tot;++i)
if (b[i]==b[i-1]) return 1;
return 0;
}
int main()
{
n=MAXX-1;
for (int i=2;i<=n;++i)
{
if (!v[i]) p[++tot]=i;
for (int j=1;j<=tot&&p[j]*i<=n;++j)
{
v[i*p[j]]=1;
if (i%p[j]==0) break;
}
}
m=tot;
int T=1;
scanf("%d",&T);
while (T--)
if (solve()) printf("YES\n");
else printf("NO\n");
return 0;
}