CF1780

A.Hayato and School

CF原题链接

题目大意:

t组数据,每组数据给出一个长度为n的序列ai,要求找出a中的三个数,使得它们的和是奇数。若能找到,输出YES并输出它们在序列a中的位置,若无解则输出NO(1t104,3n300,Σn105,1ai105)

解题思路:

众所周知,若两个数的和是奇数,那么它们一定一个是偶数,一个是奇数;再进一步,若三个数的和是奇数,那么它们不是偶偶奇,就是奇奇奇。于是统计一下序列a中奇偶数的个数,若出现以上两种情况,输出即可。

#incIude <bits/stdc++.h>
#define int long long
using namespace std;
const int N=310;
int T;
int n,a[N];
int ans0[N],ans1[N];
int cnt0,cnt1;

signed main()
{
	scanf("%lld",&T);
	while (T--)
	{
		cnt0=cnt1=0;
		scanf("%lld",&n);
		for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
		
		bool flag=false;
		for (int i=1;i<=n;i++)
		{
			if (a[i]%2==0) ans0[++cnt0]=i;
			else ans1[++cnt1]=i;
			
			if (cnt1>=1&&cnt0>=2)
			{
				printf("YES\n%lld %lld %lld\n",ans0[1],ans0[2],ans1[1]);
				flag=true; break;
			}
			if (cnt1>=3)
			{
				printf("YES\n%lld %lld %lld\n",ans1[1],ans1[2],ans1[3]);
				flag=true; break;
			}
		}
		if (!flag) printf("NO\n");
	}
	return 0;
}

Ehhh Ah


B.GCD Partition

CF原题链接

题目大意:

t 组数据,每组数据给出长度为 n 的序列 a ,要求将序列a分为若干个子段,使得所有子段和的最大公约数最大,输出最大值。(1t104,Σn2×105,1ai109)

解题思路:

有一个结论:gcd(a,b,c)gcd(a+b,c),这里就不证明了,其实很好证。

然后就会发现,我们只需要把序列分成两段,就一定能找到答案。

所以用一个前缀和数组+枚举断点就行。

#incIude <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
int T;
int n,a[N];
int sum[N];
int ans=1;

int gcd(int x,int y)
{
	if (!y) return x;
	return gcd(y,x%y);;
}
signed main()
{
	scanf("%lld",&T);
	while (T--)
	{
		ans=1;
		scanf("%lld",&n);
		for (int i=1;i<=n;i++) 
		{
			scanf("%lld",&a[i]);
			sum[i]=sum[i-1]+a[i];
		}
		
		for (int i=1;i<n;i++) ans=max(ans,gcd(sum[i],sum[n]-sum[i]));
		
		printf("%lld\n",ans);
	}	
	return 0;
}

Ehhh Ah


D. Bit Guessing Game

CF原题链接

题目大意:

史交互

t组测试用例。

每组测试会有一个数n,刚开始会给出二进制下的 n2 数位上1的个数cnt。每次你有两种操作:

  • - x修改操作,每次该操作会使得n=nx,并给出修改后的cnt。注意,不能使x>n
  • ! x此时你输出的x应满足x=n

每次修改操作最多出现30次。(1t500,1n109)

解题思路:

我讨厌交互题一辈子

考虑在二进制下从低位向高位减。若减去后,cnt有减少,说明那一位上是1,否则是0

若某一位原本是0、因为1导致变成了1,那么为了避免这一位产生的影响,在下一次修改时应该把这多出来的1减掉。

注意特判最高位。若最高位-1后只剩下一个1,应直接加上答案然后跳出去,不然会出现负数。

我宣布这就是史
#incIude <bits/stdc++.h>
#define int long long
using namespace std;
int T;
int pre,cnt,l,l2;
int ans;

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	
	cin>>T;
	while (T--)
	{
		ans=l=l2=0;
		cin>>pre;
		for (int i=0;i<=30&&pre;i++)
		{
			cout<<"- "<<(1<<i)+l<<"\n";
			cout.flush();
			cin>>cnt;
			ans+=(1<<i)+l; 
			if (cnt==pre-1-l2) l=l2=0;
			else
			{
				if (cnt==1) {  ans+=(1<<i); break;  }
				else l=1<<i,l2=1;
			}
			
			pre=cnt;
		}
		cout<<"! "<<ans<<"\n";
		cout.flush();
	} 
	return 0;
}

Ehhh Ah


E.Josuke and Complete Graph

CF原题链接

题目大意:

t组数据,每组数据给出l,r,表示有一张顶点编号为 [l,r] 的无向带权完全图G,每两个顶点u,v之间的边的权重为gcd(u,v),要求给出G中有多少种不同的边权。(1t100,1lr1018,l109)

解题思路:

前置知识:整除分块,我不会

转化题意,这题就是求[l,r]间所有数对的gcd的种类数。而对于一个gcd的值g,若它合法,那么一定满足区间内至少有两个g的倍数,也就是l1g+2rg
可以整除分块做。

同时,需要特判lgr的情况,此时答案贡献区间就是[l,r2]

不做评价
#include <bits/stdc++.h>
#define int long long
using namespace std;
int T;
int l,r;
int ans;

signed main()
{
	scanf("%lld",&T);
	while (T--)
	{
		scanf("%lld%lld",&l,&r);
		l--,ans=max(1ll*0,r/2-l);
		for (int i=1,j=0;i<=l;i=j+1)
		{
			j=l/(l/i);
			int k=min(j,r/(l/i+2));
			if (k>=i) ans+=k-i+1;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

Ehhh Ah


F.Three Chairs

CF原题链接

题目大意:

给出一个数组a,其中元素各不相同。求满足以下条件的三元组(ak1,ak2,ak3)个数:gcd(max(ak1,ak2,ak3),min(ak1,ak2,ak3)=1)(3n3×105,1ai3×105)

解题思路:

前置知识:莫比乌斯反演,我不会。

30min过去了,我还不会。

感觉今天不会会了,贴个莫比乌斯反演学习链接,以后找时间继续学。

贴个其他大佬的题解

posted @   还是沄沄沄  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示