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

Codeforces Round 868 (Div. 2)

时间:2023-04-29 10:55:15浏览次数:50  
标签:868 CI now const int Codeforces Div include deg

Preface

恭迎废物hl666终于回到了他忠诚的蓝名之位

本来这场25min切完前三题而且没挂的时候感觉状态不错的,然后D被自己的一个假做法坑了1h

最后ztc想出了大概的构造方法后已经来不及写了,一些细节没考虑好直接爆炸

本来当时就有弃D开E的想法的,但可以E的题意在公告出来之前就已经读错了,后面出了公告的时候已经决定死磕D了就没管了

不然我是打算先写E的暴力找规律的,因为前面的假题意发现连暴力都写不来

嘛不管怎么说还是自己太菜了,滚回去也是正常的说,只能再多加练习了的的说


A. A-characteristic

SB题,枚举\(1\)的个数判断即可

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=105;
int t,n,k,a[N];
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; int ret=-1; for (scanf("%d%d",&n,&k),i=0;i<=n;++i)
		if (i*(i-1)/2LL+(n-i)*(n-i-1)/2LL==k) { ret=i; break; }
		if (!~ret) { puts("NO"); continue; }
		for (puts("YES"),i=1;i<=ret;++i) putchar('1'),putchar(' ');
		for (i=ret+1;i<=n;++i) printf("-1"),putchar(' '); putchar('\n');
	}
	return 0;
}

B. Sort with Step

SB题,不难发现此时的交换只能在下标对\(k\)取模的同余系中进行

因此把每个数初始时所在的下标和最后要换到的位置的下标对\(k\)取模的值比较下,统计出不相同的对数\(cnt\)

显然若\(cnt>2\)则一定无解,否则\(cnt=0\)则直接合法,\(cnt=2\)则交换一次后有解

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005;
int t,n,k,x,pos[N];
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i; for (scanf("%d%d",&n,&k),i=1;i<=n;++i)
		scanf("%d",&x),pos[x]=i; int cur=0,x,y;
		for (i=1;i<=n;++i) if (pos[i]%k!=i%k) ++cur;
		if (cur>2) { puts("-1"); continue; }
		if (cur==0) { puts("0"); continue; }
		puts("1");
	}
	return 0;
}

C. Strongly Composite

一眼题,首先考虑先把所有数都质因数分解,求出每个质因数\(p_i\)的次数\(c_i\)

不难发现贪心地把\(c_i\)拿出两个组成一个数是合法且最优的,然后此时我们就剩下了一些次数为\(1\)余量

考虑不同的质数之间至少要\(3\)个才能组成一个合法的数,因此把剩下的三三分组即可

由于多组数据下清空数组很麻烦,所以建议直接开unordered_map

#include<cstdio>
#include<iostream>
#include<unordered_map>
#define RI register int
#define CI const int&
using namespace std;
const int N=1e7+5;
int t,n,x,pri[N],cnt; bool vis[N]; unordered_map <int,int> rst;
inline void init(CI n)
{
	RI i,j; for (i=2;i<=n;++i)
	{
		if (!vis[i]) pri[++cnt]=i;
		for (j=1;j<=cnt&&i*pri[j]<=n;++j)
		if (vis[i*pri[j]]=1,i%pri[j]==0) break;
	}
}
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t),init(1e7);t;--t)
	{
		RI i,j; for (scanf("%d",&n),rst.clear(),i=1;i<=n;++i)
		{
			for (scanf("%d",&x),j=1;j<=cnt&&pri[j]*pri[j]<=x;++j)
			if (x%pri[j]==0)
			{
				while (x%pri[j]==0) ++rst[pri[j]],x/=pri[j];
			}
			if (x>1) ++rst[x];
		}
		int ret=0,left=0; for (auto [u,v]:rst) ret+=v/2,left+=v%2;
		printf("%d\n",ret+left/3);
	}
	return 0;
}

D. Unique Palindromes

构造题腐乳闪总出列,再扯什么构造题精通我就是弱智,这下被狠狠地拷打了

首先我们要发现两个重要性质:长度为\(k\)的串最多只能有\(k\)个本质不同的回文串;只用两种字符时对于长度为\(k\)的串本质不同的回文串个数永远是\(k\)

但是我们会发现如果有三种字符结果就大不一样了,\(abcabcabc\cdots\)这个串不管长度为多少答案都是\(3\)

然后我们就由此想到一种构造原则,考虑构造的方案中回文串只能由一种字符构成,即等价于任意一种字符中间都要有两种其它的字符

再注意到一点就是\(k\)的值很小,小到比字符集大小还小,因此很容易想到每次新引入一种字符来统计次数,然后就有了大致的做法

先用\(abc\)三种字符填充第一个限制,这里可以让某个前缀字符出现次数多点来得到更多的答案,比如\(x_1=6,c_1=4\)就有构造\(aaaabc\)

然后在后面我们考虑把\(abc\)当作分隔符来用,先填充一段\(c_i-c_{i-1}\)长度的新字符后,后面就用\(abc\)的循环来填即可

不过要注意上面所提的那个要求,因此要判断下以哪个字符开头循环,具体实现可以看代码

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005,M=25;
int T,n,k,x[M],c[M]; char s[N],t[3];
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&T);T;--T)
	{
		RI i,j; scanf("%d%d",&n,&k); 
		for (i=1;i<=k;++i) scanf("%d",&x[i]);
		for (i=1;i<=k;++i) scanf("%d",&c[i]);
		bool flag=1; for (i=1;i<=k&&flag;++i) if (x[i]<c[i]) flag=0;
		if (!flag) { puts("NO"); continue; }
		auto solve=[&](CI l,CI r)
		{
			for (RI i=0;i<=r-l;++i) s[l+i]=t[i%3];
		};
		for (i=1;i<=c[1]-2;++i) s[i]='a';
		t[0]='b'; t[1]='c'; t[2]='a'; solve(c[1]-1,x[1]);
		for (i=2;i<=k;++i)
		{
			int dx=x[i]-x[i-1],dc=c[i]-c[i-1];
			if (dx<dc) { flag=0; break; }
			if (!dc)
			{
				auto find=[&](CI pos,const char& ch)
				{
					for (RI i=pos;i;--i) if (s[i]!=ch) return i;
				};
				if (s[x[i-1]]!='a'&&s[find(x[i-1]-1,s[x[i-1]])]!='a')
				t[0]='a',t[1]='b',t[2]='c'; else
				if (s[x[i-1]]!='b'&&s[find(x[i-1]-1,s[x[i-1]])]!='b')
				t[0]='b',t[1]='c',t[2]='a';	else
				t[0]='c',t[1]='a',t[2]='b';
				if (s[x[i-1]]==t[1]) swap(t[1],t[2]);
				solve(x[i-1]+1,x[i]); continue;
			}
			for (j=1;j<=dc;++j) s[x[i-1]+j]='c'+i-1;
			if (s[x[i-1]]!='a')
			t[0]='a',t[1]='b',t[2]='c'; else
			if (s[x[i-1]]!='b')
			t[0]='b',t[1]='c',t[2]='a';	else
			t[0]='c',t[1]='a',t[2]='b';
			if (s[x[i-1]]==t[1]) swap(t[1],t[2]);
			solve(x[i-1]+dc+1,x[i]);
		}
		if (!flag) { puts("NO"); continue; }
		for (puts("YES"),i=1;i<=n;++i) putchar(s[i]); putchar('\n');
	}
	return 0;
}

E. Removing Graph

很经典的博弈模型,一眼对不同大小的环求SG函数,但是前面题意看假了暴力都写不来苦路西

后面发现每次只能取一段连续的就可以写暴力了,然后这个的规律其实还是挺好找的说

先说下暴力的写法吧,设\(cycle[x]\)表示长度为\(x\)的环的SG函数,\(chain[x]\)表示长度为\(x\)的链的SG函数,转移有:

  • \(cycle[x]=\operatorname{mex}_{l\le i\le r} chain[x-i]\)
  • \(chain[x]=\operatorname{mex}_{l\le i\le r,1\le j\le x,i+j-1\le x} chain[j-1]\oplus chain[x-(i+j-1)]\)

暴力求SG函数的代码如下:

#include<cstdio>
#include<iostream>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=35;
int n,l,r,cycle[N],chain[N];
inline int Chain(CI x)
{
	if (~chain[x]) return chain[x];
	bool vis[N]; memset(vis,0,sizeof(vis));
	for (RI i=1;i<=x;++i) for (RI j=l;j<=r;++j)
	if (i+j-1<=x) vis[Chain(i-1)^Chain(x-(i+j-1))]=1;
	int mex=0; while (vis[mex]) ++mex;
	return chain[x]=mex;
}
inline int Cycle(CI x)
{
	if (~cycle[x]) return cycle[x];
	bool vis[N]; memset(vis,0,sizeof(vis));
	for (RI i=l;i<=r;++i) if (i<=x) vis[Chain(x-i)]=1;
	int mex=0; while (vis[mex]) ++mex;
	return cycle[x]=mex;
}
int main()
{
	freopen("CODE.out","w",stdout);
	for (l=1;l<=15;++l) for (r=l+1;r<=15;++r)
	{
		RI i; printf("Case %d %d\n",l,r);
		memset(cycle,-1,sizeof(cycle));	memset(chain,-1,sizeof(chain));
		for (printf("index "),i=1;i<=30;++i) printf("%-4d%c",i," \n"[i==30]);
		for (printf("chain "),i=1;i<=30;++i) printf("%-4d%c",Chain(i)," \n"[i==30]);
		for (printf("cycle "),i=1;i<=30;++i) printf("%-4d%c",Cycle(i)," \n"[i==30]);
	}
	return 0;
}

然后随便截取一段暴力的SG函数就可以发现规律:

  • 当\(x\ge l+r\)时,\(cycle[x]=0\)
  • 当\(x<l+r\)时,\(cycle[x]=\lfloor \frac{x}{l}\rfloor\)

而关于这个东西是如何推导得出的就有些复杂了,可以去Tutorial

最后代码就很好写了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005;
int n,l,r,x,y,sz[N],ret; vector <int> v[N]; bool vis[N];
inline void DFS(CI now)
{
	sz[now]=vis[now]=1; for (int to:v[now]) if (!vis[to]) DFS(to),sz[now]+=sz[to];
}
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i; for (scanf("%d%d%d",&n,&l,&r),i=1;i<=n;++i)
	scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);
	auto SG=[&](CI x)
	{
		if (x>=l+r) return 0; return x/l;
	};
	for (i=1;i<=n;++i) if (!vis[i]) DFS(i),ret^=SG(sz[i]);
	return puts(ret?"Alice":"Bob"),0;
}

F. Random Walk

做不来的期望题捏,现在这类题遇到就寄感觉只能躺好等队友了捏

首先不妨先令\(e(t)=0\),这样推出的式子形式比较统一,最后输出的时候补成\(1\)就行

一个naive的想法就是对于每个点列出转移方程,显然有:

\[e(x)=\sum_{(x,y)\in E} \frac{e(y)}{deg(y)} \]

但直接做高斯消元肯定是不可能的,我们考虑寻找一点特殊性

考虑问题的简化版本,对于一条链,起点\(s=1\),终点\(t=n\),它的解该如何构造呢

经过简单地尝试我们很容易得到答案为\(e(1)=n-1,e(2)=2(n-2),e(3)=2(n-3),\cdots,e(n-1)=2,e(n)=0\)

把这个式子调整下就变成了\(e(i)=(n-i)\times deg(i)\),然后考虑怎么把原来树上的问题转化到链上

显然由于树的优秀性质,\(s\)到\(t\)的路径一定是唯一的,然后如果我们找出这条路径后,可以以上面的点为根让剩下的点都在某个有根树中

这么做的意义何在呢,这里就有个性质,对于树上某点\(v\)与其父亲\(p\),一定有\(e(u)=\frac{deg(u)}{deg(p)}\cdot e(p)\),证明如下:

  • 若\(u\)为叶子节点,则结论显然成立
  • 否则有\(e(u)=\sum_\limits{(u,v)\in E\and v\ne p} \frac{e(v)}{deg(v)}+\frac{e(p)}{deg(p)}=\sum_\limits{(u,v)\in E\and v\ne p} \frac{deg(v)\cdot e(u)}{deg(v)\cdot dep(u)}+\frac{e(p)}{deg(p)}=\frac{deg(u)-1}{deg(u)}\cdot e(u)+\frac{e(p)}{deg(p)}\),则有\(e(u)=\frac{deg(u)}{deg(p)}\cdot e(p)\)

然后我们发现这个式子有一个很好的连乘性质,此时以\(r_i\)为根的子树内所有点\(t\)的答案就是\(e(t)=\frac{deg(t)}{deg(r_i)}\cdot e(r_i)\)

此时我们用前面的式子\(e(i)=(n-i)\times deg(i)\)算出路径上所有点的答案然后再下传到子树即可,经过检验这确实是原方程的解

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005,mod=998244353;
int n,s,t,x,y,pre[N],coef[N],E[N]; bool path[N]; vector <int> v[N];
inline void DFS1(CI now,CI fa=0)
{
	if (now==t) return; for (int to:v[now]) if (to!=fa) pre[to]=now,DFS1(to,now);
}
inline void DFS2(CI now,CI fa,CI mul)
{
	E[now]=1LL*mul*v[now].size()%mod;
	for (int to:v[now]) if (to!=fa) DFS2(to,now,mul);
}
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i; for (scanf("%d%d%d",&n,&s,&t),i=1;i<n;++i)
	scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);
	DFS1(s); path[t]=1; for (int now=t;now!=s;now=pre[now])
	coef[pre[now]]=coef[now]+1,path[pre[now]]=1;
	for (i=1;i<=n;++i) if (path[i])
	{
		for (int to:v[i]) if (!path[to]) DFS2(to,i,coef[i]);
		E[i]=1LL*coef[i]*v[i].size()%mod;
	}
	for (++E[t],i=1;i<=n;++i) printf("%d ",E[i]);
	return 0;
}

Postscript

今天晚上还有场Div2,必须一雪前耻回到紫名

不过学校的图论专题好像也是凌晨开放,如果到时候清醒的话可以抢几个一血再睡觉的说

标签:868,CI,now,const,int,Codeforces,Div,include,deg
From: https://www.cnblogs.com/cjjsb/p/17363690.html

相关文章

  • ie6 ie 8 ff 总在页脚右下角的绝对定位top div
    top.jsfunctionsetH(){varmain_div_w=1010;vardiv_w=$e('top_t').offsetWidth;vardiv_h=$e('top_t').offsetHeight;//下面二行必须定义docw3c标准varwin_w=document.documentElement.clientWidth;varwi......
  • Codeforces Round 868 (Div. 2) A-E题解
    比赛地址这把真不在状态,麻了,看来还得再练A.A-characteristic题意:给出n和k,要求构造只含1和-1数组a,存在k对(i,j)(i≠j),有a[i]*a[j]=1Solution令构造的数组有x个1和y个-1,那么其对于答案的贡献有\[x*(x-1)/2+y*(y-1)/2\]又因为有x+y=n,所以可以转化成关于x的一元二次方程化简后......
  • cf-div.2-868-D
    题目链接:https://codeforces.com/contest/1823/problem/D比赛的时候关键性质已经想到,但没想到怎么正确构造。性质:每次新加一个字母,回文子串的数量最多增加1(因为题目需要不相同的回文子串)。证明:可以用反证法,易证。构造方法:由于k的值很小(只有20),所以对于不再增加(回文子串)的......
  • Codeforces Round 867 (Div. 3)(A~D)
    目录A.TubeTubeFeed题意思路代码B.KarinaandArray题意思路代码C.BunLover题意思路代码D.Super-Permutation题意思路代码A.TubeTubeFeed题意给定时间\(t\),每个视频有一个价值\(b_i\),观看一个视频需要\(a_i\)秒,跳过一个视频需要花费\(1s\),求能观看完的价值最大......
  • Codeforces Round 867 (Div. 3)
    CodeforcesRound867(Div.3)A-TubeTubeFeed#include<bits/stdc++.h>usingnamespacestd;typedefpair<int,int>PII;typedefpair<string,int>PSI;constintN=50+5,INF=0x3f3f3f3f,Mod=1e6;constdoubleeps=1e-6;typedeflonglongll;......
  • js javascript 鼠标触碰select下拉列表渐变出div层,鼠标离开渐变缩回
    <!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><htmlxmlns="http://www.w3.org/1999/xhtml"><head><metahttp-equiv="Content-......
  • Codeforces Round 866 (Div. 1) C. The Fox and the Complete Tree Traversal (构造)
    传送门题目大意:  给定一个有n个点的树,我们可以任意选择一个点作为起点,这个点可以跳到跟自己距离为1或者距离为2的点,已经到达的点不能再到达(最终必须回到起点),询问是否存在一种方案可以从一个点出发经过所有的点最终再回到这个点来。  输入一个整数n。紧接着输入n-1条边。大......
  • Codeforces Round 847 (Div. 3) G.Tokens on Graph (构造)
    传送门题目大意  给定一个无向图,我们定义图中有四种点,一种是黑色的点表示终点,并且黑色的点始终是1号点,一种是红色的点,一种是灰色的点,最后一种就是没有颜色的点。  游戏规则:我们必须移动任意一个灰色的点到相邻的点上,如果灰色的点移动到了红色的点上,那么我们可以移动其他灰......
  • 前端隐藏和显示div的方式js和beetle:
    方式一:设置元素style对象中的display属性1、vart=document.getElementById('demo');//选取id为test的div元素2、t.style.display='none';//隐藏选择的元素3、t.style.display='block';//以块级样式显示方式二:设置元素style对象中的visibility属性1、vart=documen......
  • 让CSS里div上下左右绝对居中几种方式
    1、绝对定位(常用于登录模块)备注:前提条件div需要有宽高1<divclass="box"></div>2#css3.box{4position:absolute/fixed;5left:0;6right:0;7top:0;8bottom:0;9margin:auto;10}2、margin负值备注:前提条件div需要有宽高1<divclass="box"&g......