首页 > 其他分享 >Codeforces Round 959 sponsored by NEAR (Div. 1 + Div. 2)

Codeforces Round 959 sponsored by NEAR (Div. 1 + Div. 2)

时间:2024-07-19 16:00:23浏览次数:7  
标签:959 数字 ll 位置 Codeforces long Div 贪心 getchar

A直接速通就好了,我第一眼看的时候以为是整个数组可以有重复的数字,后面发现是保证没有的,所以直接随便交换一下位置就结束了。

B,很经典的CF题,随便推导一下就能够发现,如果我想要一个位置能够发生变化,那么唯一的要求就是他以及他前面的位置有1出现过。而且完全不需要考虑为了一个数字变化而引起的其他位置的变化无法解决,如果这个位置原本是0变成了1,那直接让它异或一次他本身即可,如果是1变成了0,那么如果前面有1存在,就是重复操作就好了。所以我们只需要找到第一个需要改变的位置,然后看是否有1已经在这个位置或之前出现过就可以判断答案。

C,一个简单的dp,\(f[i]\)表示从1到\(i\)的位置,有多少个位置能够满足从这个位置开始一直累加到\(i\)这个位置,在累加完\(i\)这个位置后变为\(0\)。
然后这个数组的总和就是所有的无法完成的情况。也就是答案的补集,直接用\(n*(n-1)/2\)减去即可。具体过程可以使用在前缀和上二分完成转移。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
	ll a=0,b=1;char c=getchar();
	for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
	for(;c>='0'&&c<='9';c=getchar())a=a*10+c-'0';
	return a*b;
}
ll a[200010],n,k,l,r;
ll Sum[200010],f[200010];
ll flag=0;
inline ll getSum(ll x,ll y) ;
int main()
{
	ll T=read();
	while(T--)
	{
		n=read(),k=read();
		for(ll i=1;i<=n;i++)
		{
			a[i]=read();
			Sum[i]=Sum[i-1]+a[i];
			f[i]=0;
		}
		f[n+1]=0;ll Ans=0,ans;
		for(ll i=1;i<=n;i++)
		{
			l=i,r=n;
			while(l<=r)
			{
				ll mid=l+r>>1;
				ll Get=getSum(i,mid);
				if(Get>k)
				{
					r=mid-1;
				}
				else 
				{
					l=mid+1;
				}
			}
			Ans+=f[i];
			f[l+1]+=f[i]+1;
		}
		Ans+=f[n+1];
		ans=n*(n+1LL)/2-Ans;
		cout<<ans<<endl;
	}
	return 0;
}
inline ll getSum(ll x,ll y)
{
	if(x>y)return 0;
	return Sum[y]-Sum[x-1];
}

D,赛时开始没做出来了。
首先是一个很简单也很重要的贪心,\(b-a\)是\(x\)的倍数,等价与\(b\)与\(a\)在\(\mod x\)的意义下相等。
这个在这题里面虽然作用不是特别关键,但是其实是非常重要的。
还有一个比较重要的事情,就是0是可以被任何数字整除的。这意味着,对于\(n\)个数字,一定存在两个数字在\(\mod n-1\)的意义下相等。
证明的话,我们就用\(1\)到\(n\)这\(n\)个数字举例,很明显,\(1\)和\(n\)在\(\mod n-1\)的意义下相等,如果我们无法把其中一个数字用另一个替换并且不产生其他在这个意义下相等的数字,就可以说明成立。任何我们发现,0可以被任何数字整除,也就是无法有相等的数字出现,否则他们一定可以被选取,那么剩下便没有位置了。也就是一定存在两个数字能够达成这个条件。

也就我们从最后一个\(n-1\)的条件开始使用,一定每次都能够连一条边,不存在无法连接的情况。
但是为什么不会出现环而导致生成树无法出现呢?

其实非常简单。连接完两个点之后,直接删掉里面的任意一个点,对于剩下的n-1个点,我们是取模n-2意义下的,依旧是一定能够出现答案的。所以,连接完之后,任意标记里面的一个点,然后连接的时候只需要找到没有被标记的点连接即可。

主要就是这个对于\(n\)个数字,一定存在两个数字在\(\mod n-1\)的意义下相等的结论的运用。
手玩其实就能看出来?

唉。变菜了。
不过学到了吧,也是。
这么简单的一个贪心,是我状态不好还是我对于生成树的理解确实不够呢?其实是对于那个前置的贪心的应用不够,一定存在,就是真的一定。不管怎么删去点都是一定存在的。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
	int a=0,b=1;char c=getchar();
	for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
	for(;c>='0'&&c<='9';c=getchar())a=a*10+c-'0';
	return a*b;
}
int used[2001],vis[2001],n,a[2001];
int x[2001],y[2001],tot;
int main()
{
	int T=read();
	while(T--)
	{
		n=read();tot=0;
		for(int i=1;i<=n;i++)
		{
			a[i]=read();used[i]=0;
		}
		for(int i=n-1;i>=1;i--)
		{
//			if(used[i])continue;
			for(int j=0;j<i;j++)vis[j]=0;
			for(int j=1;j<=n;j++)
			{
				if(used[j])continue;
				int t=a[j]%i;
				if(vis[t])
				{
//					cout<<vis[t]<<' '<<j<<endl;
					x[++tot]=vis[t];
					y[tot]=j;
					used[j]=1;
					break;
				}
				else 
				{
					vis[t]=j;
				}
			}
		}
//		for(int i=1;i<=n;i++)
//		{
//			cout<<used[i]<<' ';
//		}
//		cout<<endl;
		cout<<"Yes"<<endl;
		for(int i=tot;i>=1;i--)
		{
			cout<<x[i]<<' '<<y[i]<<endl;
		}
		tot=0;
	}
	return 0;
}

E题,更是。。。炸裂,我觉得比D简单。

首先是cf经典前置贪心。对于单棵树,直接全取绝对最优。

然后考虑森林,可以发现,对于体积最大的那个树,怎么做也不可能让这个最大的数的最高位之上的二进制位变为1 。
所以最优秀的情况就是体积最大的直接全取,然后下面的尝试填补中间的1 。
然后就要用到那个砍树的操作了。我们完全没有必要砍子树。直接砍叶子,把这棵树砍成想要的大小。只动叶子,每次-1,而且每次都一定能够操作,所以我可以得到一个小于这树的任意大小的树。
那这个贪心,可以说是非常非常简单了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
	ll a=0,b=1;char c=getchar();
	for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
	for(;c>='0'&&c<='9';c=getchar())a=a*10+c-'0';
	return a*b;
}
ll n,a[1000001];
int main()
{
	ll T=read();
	while(T--)
	{
		n=read();ll ans=0;
		for(ll i=1;i<=n;i++)
		{
			a[i]=read();
			for(ll j=1;j<a[i];j++)read();
		}
		sort(a+1,a+1+n);
		for(ll i=21;i>=0;i--)
		{
			ll Sum=0;
			for(int j=1;j<=n;j++)
			{
				if((a[j]>>i)&1)
				{
					Sum++;
				}
			}
//			cout<<Sum<<endl;
			if(Sum>=2)
			{
				ans|=((1<<i+1)-1);
			}
			else
			if(Sum==1)
			{
				ans|=(1<<i);
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

破防了。。。本来上大分的。。。。

标签:959,数字,ll,位置,Codeforces,long,Div,贪心,getchar
From: https://www.cnblogs.com/HLZZPawa/p/18311636

相关文章

  • Round 959
    A给定\(n*m\)数组\(a\),$1\lea_i\len*m$并且两两不同,问是否存在数组\(b\),也使用这些元素,并且每个位置的值都与\(a\)不同。\(1*1\)数组特判,其他循环移位。B给定01串s和t,可以对s任意次执行以下操作:选择l,r,将l,r异或等长前缀,问s和t是否能相等对于s和t第一个不同的位置......
  • Educational Codeforces Round 139 (Rated for Div. 2)
    A.ExtremelyRound----------------------------------题解-------------------------------------因为数据范围只有1e6,我们只需要预处理出来1-1e6每个每个数包含多少个极圆整数就行了,然后t次查询就可以。这种预处理查询是面对多次询问时应该首先想到的。点击查看代码#incl......
  • 题解:CF1912D Divisibility Test
    又是一道水绿。刚刚小学毕业的数学idiot——我释怀地笑了。第一种很好判断,当$b^k$为$n$的倍数时,取基数为$b$的能被$n$整除的整数$c$的最后$k$位数显然能被$n$整除。第二种也不难,当$b^k\equiv1\pmodn$时,取以$b$为底数的能被$n$整除的整数$c$的$k$......
  • Divide Interval 题解
    背景太逊了,调了三次才调出来,所以写篇题解寄念。LC好睿智题意给你两个数\(a,b\),现在要从\(a\)跑到\(b\),每次可以将当前的\(a\)拆分成\(2^n\timesm(n,m\inN)\)的形式,并将它变成\(2^n\times(m+1)\)。问最少变几次能跑到\(b\),输出次数和每次变化前后\(a\)的值。分......
  • CodeForces Round 898 (div 4) H题解析
     CodeForcesRound898(div4)H.Mad City                           大致思路   对于有n条边和n个点,说明这个图里面只有一个环并且两人同时开始和结束移动,所以可以得到当Valeriu进入到这个图里面的唯一......
  • Codeforces Round 958 (Div. 2)
    题目链接:CodeforcesRound958(Div.2)总结:C因为常数没转\(longlong\)\(wa\)两发,难绷。A.SplittheMultisetfag:模拟Description:给定一个\(n\)和一个\(k\),每次可以将\(n\)减掉一个数\(u\),然后插入\(x\)个数,\(x<=k\),并且插入的数之和等于\(u\)。求将其转化为全\(1\)的最......
  • Codeforces Round 957 (Div. 3)
    知识点1.几个数相乘时,更小的数增加会比更大的数增加得到的乘积来得大题解A.OnlyPluses1.几个数相乘时,当更小的数增大时,得到的乘积会比更大的数增大来得大,也就是更小的数字权重会比较大,那么在5次+1的过程中,每次找最小值++即可#include<bits/stdc++.h>#defineintlonglon......
  • Codeforces Round 898 (Div. 4)(A~H)
    目录A.ShortSortB.GoodKidC.TargetPracticeD.1DEraserE.BuildinganAquariumF.MoneyTreesG.ABBCorBACBH.MadCityA.ShortSortProblem-A-Codeforces暴力枚举每个位置的交换即可。#include<iostream>#include<algorithm>#include<queue......
  • Codeforces Round 957 (Div. 3)
    题目链接:CodeforcesRound957(Div.3)总结:E不懂,F差一个set去重A.OnlyPlusesfag:枚举B.AngryMonkfag:模拟Solution:分裂的花费为\(a_i-1\),添加的花费为\(a_i\)。C.GorillaandPermutationfag:思维Solution:大于等于\(k\)的数,逆序放在最前面,小于等于\(m\)的数,从最后面......
  • Codeforces Round 958 (Div. 2)补题
    文章目录A题(拆分多集)B题(获得多数票)C题(固定OR的递增序列)A题(拆分多集) 本题在赛时卡的时间比较久,把这题想复杂了,导致WA了两次。后来看明白之后就是将n每次转换成k-1个1,到最后分不出来k-1个1直接一次就能分完,即结果加一;#include<bits/stdc++.h>#definein......