Codeforces Round 869 (Div. 2)

Preface

一把回到紫名还是很舒服的,D题手比较稳猜了点性质水过

主要还是C脑抽了想了挺久才看出来是个丁真题,不然最后过了D之后30min可以看看E的

由于要写学校的图论专题所以接下来一段时间的CF补题计划就要先停一停了


A. Politics

傻逼题,当某个人的串和第一个人有任意一个位置不同时,它就肯定得被请出去

所以看有多少个串和第一个人的串相同即可

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=105;
int t,n,k; char s[N][N]; bool vis[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%d",&n,&k),i=1;i<=n;++i) vis[i]=1,scanf("%s",s[i]+1);
		for (j=1;j<=k;++j) for (i=1;i<=n;++i) if (s[i][j]!=s[1][j]) vis[i]=0;
		int ret=0; for (i=1;i<=n;++i) ret+=vis[i]; printf("%d\n",ret);
	}
	return 0;
}

B. Indivisible

原来还真有这种可以递推的构造题

首先发现\(n\)为奇数时除了\(n=1\)之外一定无解,因为长度为\(n\)的区间必然不满足要求

否则考虑偶数的情况,我们可以从\(n-2\)的构造情况转移过来

一种合法的方案是类似这样,正确性很容易验证:

\[2,1,4,3,6,5\cdots \]

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

C. Almost Increasing Subsequence

刚开始各种想复杂结果卡了快40min,不然这场分还能涨

首先容易发现我们可以把一段连续的不升区间放在一起考虑,比如样例就可以划分成:

\[(1),(2),(4,3,3),(5),(6,2,1) \]

不难发现每一段长度大于等于\(2\)的区间取首尾一定是最优的,因此把长度大于等于\(2\)的区间赋权值\(2\),等于\(1\)的区间赋权值\(1\)

那么询问的时候只要求这段区间的权值和即可,不过要注意两个端点所在的区间的情况要讨论下

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005;
int n,q,a[N],pos[N],sz[N],cnt,pfx[N],l,r;
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i,j; for (scanf("%d%d",&n,&q),i=1;i<=n;++i) scanf("%d",&a[i]);
	int lst=1; for (i=2;i<=n;++i) if (a[i]>a[i-1])
	{
		for (++cnt,j=lst;j<=i-1;++j) pos[j]=cnt,++sz[cnt]; lst=i;
	}
	for (++cnt,j=lst;j<=n;++j) pos[j]=cnt,++sz[cnt];
	for (i=1;i<=cnt;++i) pfx[i]=pfx[i-1]+min(sz[i],2);
	for (i=1;i<=q;++i)
	{
		scanf("%d%d",&l,&r); if (pos[l]==pos[r])
		printf("%d\n",l==r?1:2); else
		{
			int ret=pfx[pos[r]-1]-pfx[pos[l]];
			ret+=sz[pos[l]]==1?1:(a[l+1]<=a[l]?2:1);
			ret+=sz[pos[r]]==1?1:(a[r-1]>=a[r]?2:1);
			printf("%d\n",ret);
		}
	}
	return 0;
}

D. Fish Graph

花式猜结论直接水过可海星,果然图论的本质就是猜结论吗(doge

首先很容易想到BF的做法,对于每个度数大于等于\(4\)的点\(u\),枚举两个相邻点当尾巴后在剩下的点里找一个过\(u\)的环

但这样的复杂度显然会炸穿,其实我比赛的时候还交了一发喜提TLE

直觉告诉我们应该直接找环然后判断是否存在两个不在环上的点,但如果我们随便找环的话可能会因为DFS的性质把本来可以剩下来的点给占用掉

然后一个很自然的想法就是要找长度最小的环,然后可以证明这样是一定能出解的

因为我们只要找到这个点在环上的两个相邻点,那么最小长度的构造方案一定只占用其中的两个相邻点,否则我们一定可以删去其中的某些点

现在的问题就是怎么找长度最小的环,解决方法大概可以用BFS判环法?

不过由于我前面已经写了DFS判环的代码了,所以加个迭代加深就行

#include<cstdio>
#include<iostream>
#include<vector>
#define RI register int
#define CI const int&
using namespace std;
const int N=2005;
int t,n,m,x,y,pre[N],cnt,ansx[N],ansy[N]; bool vis[N]; vector <int> v[N];
inline bool find_cycle(CI now,CI tar,CI len,CI lim,CI lst=0)
{
	if (len>lim) return 0; for (int to:v[now])
	if (to!=lst&&to==tar) return pre[to]=now,1; else if (!vis[to])
	{
		vis[to]=1; pre[to]=now;
		if (find_cycle(to,tar,len+1,lim,now)) return 1; vis[to]=0;
	}
	return 0;
}
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	for (scanf("%d",&t);t;--t)
	{
		RI i,j,k; for (scanf("%d%d",&n,&m),i=1;i<=m;++i)
		scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);
		bool flag=0; for (i=1;i<=n&&!flag;++i) if (v[i].size()>=4)
		{
			for (j=1;j<=n;++j) vis[j]=0; vis[i]=1;
			if (!find_cycle(i,i,1,n)) continue;
			for (k=3;k<=n&&!flag;++k)
			{
				for (j=1;j<=n;++j) vis[j]=0; vis[i]=1;
				if (find_cycle(i,i,1,k))
				{
					cnt=0; for (int v:v[i])	if (!vis[v])
					{
						++cnt; ansx[cnt]=i; ansy[cnt]=v;
						if (cnt==2) break;
					}
					if (cnt<2) break;
					int now=i; for (;pre[now]!=i;now=pre[now])
					++cnt,ansx[cnt]=now,ansy[cnt]=pre[now];
					++cnt; ansx[cnt]=i; ansy[cnt]=now;
					for (printf("YES\n%d\n",cnt),i=1;i<=cnt;++i)
					printf("%d %d\n",ansx[i],ansy[i]); flag=1;
				}
			}
		}
		if (!flag) puts("NO");
		for (i=1;i<=n;++i) v[i].clear();
	}
	return 0;
}

E. Similar Polynomials

多项式题,比赛的时候题目没细看就去看学校的图论专题的题了,赛后对着题解补的QWQ(以下所有等式都指模运算下)

首先两个相似多项式的最高次项的系数一定相同,不妨都设为\(k\),然后考虑次高次项,即写出形式:

\[A(x) = \dots + a x^{d-1} + k x^d,B(x) = \dots + b x^{d-1} + k x^d \]

然后由于题目中提到的性质,\(B(x)=A(x+s)\),所以有\(B(x-s) = \dots + (b-k s d)x^{d-1} + x^d\)

这里后面的展开就是个二项式定理,就不过多赘述了

因此由比较系数法我们发现令\(k=[x^d]A(x),a=[x^{d-1}]A(x),b=[x^{d-1}]B(x)\),则\(a=b-ksd\),即\(s=\frac{b-a}{kd}\)

所以现在的问题就是一个给出多项式的点值求系数的问题了,根据拉格朗日插值的姿势(这篇博客个人觉得还是写的挺好挺详细的),由于这里是连续正数位置的点值,因此:

\[[x^{d}]f(x) = \sum\limits_{i=0}^d y_i \prod\limits_{j \neq i} \frac{1}{x_i - x_j} = \sum\limits_{i=0}^d y_i \prod\limits_{j \neq i} \frac{1}{i-j} = \sum\limits_{i=0}^d y_i \frac{(-1)^{d-i}}{i! (d-i)!} \]

直接令\(c_i = \frac{(-1)^{d-i}}{i! (d-i)!}\)即可计算出\(k\)的值了:

\[[x^d] f(x) = \sum\limits_{i=0}^d y_i c_i \]

对于\(d-1\)次项的计算我们可以观察到:

\[[x^{d-1}] (x-x_1) \dots (x-x_d) = -(x_1 + \dots + x_d) \]

所以有:

\[[x^{d-1}]f(x) = -\sum\limits_{i=0}^d y_i c_i \sum\limits_{j \neq i} j = -\sum\limits_{i=0}^d y_i c_i \left(\frac{d(d+1)}{2} - i\right) \]

然后就可以直接算了,总复杂度\(O(d)\)

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=2500005,mod=1e9+7;
int d,fact[N],ifac[N],A[N],B[N],C[N],k,a,b;
inline void inc(int& x,CI y)
{
	if ((x+=y)>=mod) x-=mod;
}
inline void dec(int& x,CI y)
{
	if ((x-=y)<0) x+=mod;
}
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 (ifac[n]=quick_pow(fact[n]),i=n-1;~i;--i) ifac[i]=1LL*ifac[i+1]*(i+1)%mod;
}
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i; for (scanf("%d",&d),init(d),i=0;i<=d;++i) scanf("%d",&A[i]);
	for (i=0;i<=d;++i) scanf("%d",&B[i]);
	for (i=0;i<=d;++i) if (C[i]=1LL*ifac[i]*ifac[d-i]%mod,(d-i)&1) C[i]=mod-C[i];
	int tmp=1LL*d*(d+1)/2LL%mod; for (i=0;i<=d;++i)
	inc(k,1LL*A[i]*C[i]%mod),dec(a,1LL*A[i]*C[i]%mod*(tmp-i+mod)%mod),dec(b,1LL*B[i]*C[i]%mod*(tmp-i+mod)%mod);
	return printf("%d",1LL*(b-a+mod)*quick_pow(1LL*k*d%mod)%mod),0;
}

Postscript

真得珍惜这坎坷的紫名了,希望别下场又滚回去了的说

posted @ 2023-05-01 15:40  空気力学の詩  阅读(148)  评论(2编辑  收藏  举报