首页 > 其他分享 >Codeforces Round 875 (Div. 2)

Codeforces Round 875 (Div. 2)

时间:2023-05-29 20:46:53浏览次数:39  
标签:CI const int 875 Codeforces Div include RI define

Preface

难得现场打一次,这天下午打了三个半小时的校内赛,然后八点打了两小时ARC,最后再接上两个半小时的CF真是爽歪歪

不过有一说一其实很多时候都在坐牢,这场CF也差不多,一个小时写完ABCD然后开始坐牢,其实E基本想出来了但是没想到用随机赋值的方法来实现

不过由于这场手很稳因此排名极高(Div2 Rank22),因此上了波大分(小号分数要直逼大号了)


A. Twin Permutations

直接令\(b_i=n+1-a_i\),这样最后所有的\(a_i+b_i\)都为\(n+1\),满足题意

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=105;
int t,n,a[N];
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&a[i]);
		for (i=1;i<=n;++i) printf("%d%c",n+1-a[i]," \n"[i==n]);
	}
	return 0;
}

B. Array merging

屌题面写的有点难懂,猜了几分钟才猜出题意

开两个桶分别统计下两个串中每种数的最长连续段长度,然后贡献就直接相加即可

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=400005;
int t,n,a[N],b[N],ca[N],cb[N];
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; for (scanf("%d",&n),i=1;i<=2*n;++i) ca[i]=cb[i]=0;
		for (i=1;i<=n;++i) scanf("%d",&a[i]);
		for (i=1;i<=n;++i) scanf("%d",&b[i]);
		int lst=0; for (a[n+1]=0,i=1;i<=n;++i)
		if (a[i]!=a[i+1]) ca[a[i]]=max(ca[a[i]],i-lst),lst=i;
		lst=0; for (b[n+1]=0,i=1;i<=n;++i)
		if (b[i]!=b[i+1]) cb[b[i]]=max(cb[b[i]],i-lst),lst=i;
		int ret=0; for (i=1;i<=2*n;++i) ret=max(ret,ca[i]+cb[i]);
		printf("%d\n",ret);
	}
	return 0;
}

C. Copil Copac Draws Trees

设\(f_i\)表示给\(i\)染色需要的最少轮数,然后按照题面所给的顺序给每条边一个权值

令\(u\)的父边权值为\(lst\),对于\(u\to v\)这条边,显然有转移\(f_v=f_u+[w<lst]\),直接DFS一遍即可

#include<cstdio>
#include<iostream>
#include<vector>
#include<utility>
#define RI register int
#define CI const int&
using namespace std;
typedef pair <int,int> pi;
const int N=200005;
int t,n,x,y,f[N]; vector <pi> v[N];
inline void DFS(CI now=1,CI fa=0,CI lst=0)
{
	for (auto [to,w]:v[now]) if (to!=fa) f[to]=f[now]+(w<lst),DFS(to,now,w);
}
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; for (scanf("%d",&n),i=1;i<=n;++i) v[i].clear();
		for (i=1;i<n;++i) scanf("%d%d",&x,&y),v[x].push_back(pi(y,i)),v[y].push_back(pi(x,i));
		int ret=0; for (f[1]=1,DFS(),i=1;i<=n;++i) ret=max(ret,f[i]);
		printf("%d\n",ret);
	}
	return 0;
}

D. The BOSS Can Count Pairs

这场说实话运气挺好的,D是比较擅长的根号分治的题所以一看到就会了,然后交之前也调对了各种参数一发入魂(其实E也挺合胃口的,就是做了那么多随机赋权的题这次没想到,可能是因为对排名没啥影响所以摆了)

回到这题由于\(a_i,b_i\le n\),因此等式的右边的和式最大值也就\(2n\),而左边又是个乘法,因此很容易想到根号分治

设阈值\(S\),当\(a_i>S\)时,很显然\(a_j\)的取值只有\(\frac{2n}{S}\)种,我们可以从后往前扫一遍,对于每种\(a_j\),用一个桶来存它们对应的\(b_j\)出现的次数

刚开始这里写unordered_map的,不过后面一想时限很紧所以就先没交,然后发现可能产生贡献的\(a_j\le \frac{2n}{S}\),因此可以暴力开数组来存(但是要注意别爆内存了)

当\(a_i\le S\)时,我们可以直接枚举一个\(t\in[1,S]\),然后从左往右扫,遇到\(a_i=t\)就用桶记录下\(b_i\)出现的次数,然后再对每个数都进行统计即可

重点注意以上的两次操作的枚举顺序不能错,否则会出现多算或者少算的问题

复杂度的话,理论上取\(S=\sqrt{2n}\)是最优的,但这样数组会开不下,因此我选的是\(S=1000\),然后这样\(400\times 200000\)的int数组刚好能开下,最后跑了\(1856ms\)

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005,S=1000;
int t,n,a[N],b[N],c[N],f[405][N];
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i,j; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&a[i]);
		for (i=1;i<=n;++i) scanf("%d",&b[i]); long long ret=0;
		for (i=1;i<=S;++i)
		{
			for (j=1;j<=n;++j) c[j]=0;
			for (j=1;j<=n;++j)
			{
				if (1LL*i*a[j]-b[j]>=1&&1LL*i*a[j]-b[j]<=n) ret+=c[i*a[j]-b[j]];
				if (a[j]==i) ++c[b[j]];
			}
		}
		for (i=n;i>=1;--i)
		{
			if (a[i]>S) for (j=1;a[i]*j<=2*n;++j)
			if (a[i]*j-b[i]>=1&&a[i]*j-b[i]<=n) ret+=f[j][a[i]*j-b[i]];
			if (a[i]<=400) ++f[a[i]][b[i]];
		}
		for (i=1;i<=n;++i) if (a[i]<=400) --f[a[i]][b[i]];
		printf("%lld\n",ret);
	}
	return 0;
}

E. Hyperregular Bracket Strings

这场主要赛时后面两题过的人太少了(到结束E题9人,F题Div2都没人过),所以默认自己写不出来就弃了,其实今天一看不难的说

首先很容易发现当所有区间都不交的时候答案就是独立的,每一部分用卡特兰数求一下方案数然后乘起来就好

然后思考区间有交的情况,不难发现两个区间的交一定也必须是合法的括号序列,而且这部分的贡献计算就会和原来的独立开来

为什么区间的交也必须是合法的呢,其实可以用括号序列的经典模型,即把左括号看成\(1\),右括号看成\(-1\)

然后合法括号序列满足前缀和全部\(\ge 0\),后缀和全部\(\le 0\),然后当两个合法括号序列区间相交时,中间那一段就一定是也满足上面的限制,因此它也必须是合法的

因此这题的思路就很清楚了,我们设最后每个位置\(i\),覆盖它的区间标号集合为\(S_i\),则所有\(S\)相同的位置都要被一起考虑

然后我当时以为是线段树分治维护区间覆盖,然后判重复就歇逼了,难不成要mapvector

后来一看捏麻麻的这个套路之前做过不知道多少次了,直接给每个区间随机一个权值,然后覆盖就直接给每个位置异或上这个值即可

最后根据每个点的权值来分类即可,实现的话直接用差分,非常好写

#include<cstdio>
#include<iostream>
#include<random>
#include<map>
#define RI register int
#define CI const int&
using namespace std;
typedef unsigned long long ull;
const int N=300005,mod=998244353;
int t,n,m,fact[N],ifact[N],l,r; ull pfx[N]; map <ull,int> rst;
mt19937_64 rnd(random_device{}());
uniform_int_distribution<ull> dist(0,ULLONG_MAX);
inline int quick_pow(int x,int p=mod-2,int mul=1)
{
	for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
inline void init(CI n)
{
	RI i; for (fact[0]=i=1;i<=n;++i) fact[i]=1LL*fact[i-1]*i%mod;
	for (ifact[n]=quick_pow(fact[n]),i=n-1;~i;--i) ifact[i]=1LL*ifact[i+1]*(i+1)%mod;
}
inline int C(CI n,CI m)
{
	return 1LL*fact[n]*ifact[m]%mod*ifact[n-m]%mod;
}
inline int Catalan(CI x)
{
	if (x&1) return 0; return (C(x,x/2)-C(x,x/2-1)+mod)%mod;
}
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (init(300000),scanf("%d",&t);t;--t)
	{
		RI i; for (scanf("%d%d",&n,&m),i=1;i<=n;++i) pfx[i]=0;
		for (i=1;i<=m;++i)
		{
			scanf("%d%d",&l,&r); ull x=dist(rnd);
			pfx[l]^=x; pfx[r+1]^=x;
		}
		for (rst.clear(),i=1;i<=n;++i) ++rst[pfx[i]^=pfx[i-1]];
		int ret=1; for (auto [_,x]:rst) ret=1LL*ret*Catalan(x)%mod;
		printf("%d\n",ret);
	}
	return 0;
}

Postscript

妈的要考离散了,一堆定理和专有名词的英文名一点没背,准备吃席

标签:CI,const,int,875,Codeforces,Div,include,RI,define
From: https://www.cnblogs.com/cjjsb/p/17441605.html

相关文章

  • CF1292 div.1 做题记录
    ACF题面若某一列的第\(i\)行禁止移动,那么看另一列的第\(i-1,i,i+1\)行是否存在禁止移动的格子,若存在为No,否则为Yes,这个只需要在改变一个点状态时判断即可。点击查看代码#include<bits/stdc++.h>#defineullunsignedlonglong#definelllonglong#definepiipair......
  • cf-div.2-875d
    链接:https://codeforces.com/contest/1831/problem/D脑子确实不好使,没啥思路,看jls代码之后豁然开朗。思路:先枚举约数s,因为\(b_i+b_j\)不会超过4e5,所以第一层枚举所有约数为根号级别,第二层循环里枚举所有对数,统计\(v=a_i*s-b_i\)的所有个数,只有当\(a_i\)的值与s的值相等时,才能......
  • Codeforces Round 874 (Div. 3)
    A.MusicalPuzzle#include<bits/stdc++.h>usingnamespacestd;voidsolve(){intn;strings;cin>>n>>s;set<string>cnt;for(inti=0;i+1<n;i++)cnt.insert(s.substr(i,2));......
  • Codeforces Round 875 (Div. 2) A-D
    CodeforcesRound875(Div.2)A.TwinPermutationsinta[N];voidsolve(){intn=read();for(inti=1;i<=n;i++)a[i]=read();for(inti=1;i<=n;i++)cout<<n+1-a[i]<<'';cout<<'\n';//puts(ans&g......
  • CodeForces 1830C Hyperregular Bracket Strings
    洛谷传送门CF传送门每一步思路都非常自然的题。考虑先从一些简单的case入手。1.\(k=0\)设\(g_i\)为长度为\(i\)的合法括号串数。显然\(\foralli\nmid2,g_i=0\)。对于偶数的\(i\),这是一个经典问题,\(g_i\)就是第\(\frac{i}{2}\)项卡特兰数,因此\(g_i=\bi......
  • Codeforces Round #875 (Div. 2)
    CodeforcesRound#875(Div.2)bilibili:CodeforcesRound#875(Div.2)实况|完成度[4.01/6]A#include<bits/stdc++.h>usingll=longlong;usinguint=unsigned;usingnamespacestd;intTestCase;signedmain(){ for(scanf("%d",&......
  • Codeforces Round 875 (Div. 2) A~D
    CodeforcesRound875(Div.2)A~DA.TwinPermutations构造\(a[i]+b[i]=n+1\)voidwork(){ intn; cin>>n; rep(i,1,n){ intx; cin>>x; cout<<n-x+1<<""; } cout<<endl;}B.Arraymerging......
  • HTML中让上下两个div之间保持一定距离或没有距离
    这篇文章主要为大家详细介绍了HTML让上下两个DIV之间保持一定距离或没有距离,可以用来参考一下。1、若想上下DIV块之间距离,只需设定:在CSS里设置DIV标签各属性参数为0div{margin:0;border:0;padding:0;}这里就设置了DIV标签CSS属性相当于初始化了DIV标签CSS属性,这里设置margin外......
  • Educational Codeforces Round 149 (Rated for Div. 2)(A~F)
    A.GrasshopperonaLine题意:给出n,k,从0开始,每次可以加一个数,最快到达n需要,输出首先跳几次,然后每次跳多少,限制只有一个跳的长度不能整除k。分析:n%k,有余直接跳,没余数,先跳一个,再跳剩余的长度。代码:#include<cstring>#include<iostream>#include<algorithm>usingnamespac......
  • 29. Divide Two Integers刷题笔记
    参考的题解classSolution:defdivide(self,dividend:int,divisor:int)->int:positive=(dividend<0)is(divisor<0)dividend,divisor=abs(dividend),abs(divisor)res=0whiledividend>=divisor:......