Codeforces Round #775 (Div. 2) Solution Set

暂时只有 Div. 2。

CF1649A Game

显然要找到最长的前缀和后缀是 \(1\),然后中间跳过去。特判全是 \(1\) 的情况,不需要花费。

/*
他决定要“格”院子里的竹子。于是他搬了一条凳子坐在院子里,面对着竹子硬想了七天,结果因为头痛而宣告失败。
DONT NEVER AROUND . //
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
int read()
{
	int x=0;
	char c=getchar();
	while(c<'0' || c>'9')	c=getchar();
	while(c>='0' && c<='9')	x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
	return x;
}
void write(int x)
{
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
const int MOD=998244353;
inline int Add(int u,int v){return u+v>=MOD?u+v-MOD:u+v;}
inline int Sub(int u,int v){return u-v>=0?u-v:u-v+MOD;}
inline int Mul(int u,int v){return LL(u)*LL(v)%MOD;}
int QuickPow(int x,int p)
{
	if(p<0)	p+=MOD-1;
	int ans=1,base=x;
	while(p)
	{
		if(p&1)	ans=Mul(ans,base);
		base=Mul(base,base);
		p>>=1;
	}
	return ans;
}
int a[105],n;
void Solve()
{
	n=read();
	int x=0;
	for(int i=1;i<=n;++i)	x+=(a[i]=read());
	if(x==n)
	{
		puts("0");
		return ;
	}
	int sum=n+1;
	for(int i=1;i<=n;++i)
	{
		if(!a[i])	break;
		--sum;
	}
	for(int i=n;i;--i)
	{
		if(!a[i])	break;
		--sum;
	}
	write(sum),puts("");
}
int main(){
	int T=read();
	while(T-->0)	Solve();
	return 0;
}

CF1649B Game of Ball Passing

既然官方的 Sol 也声称在猜结论,那我也猜结论吧。

特判没传球的情况,然后考虑最大值 \(p\) 和总传球数 \(s\) 的关系。

如果 \(2p\leq s\),答案是 \(1\);否则最大值需要踢出去 \(2p-s\) 个球,答案也是 \(2p-s\)

/*
他决定要“格”院子里的竹子。于是他搬了一条凳子坐在院子里,面对着竹子硬想了七天,结果因为头痛而宣告失败。
DONT NEVER AROUND . //
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
LL read()
{
	LL x=0;
	char c=getchar();
	while(c<'0' || c>'9')	c=getchar();
	while(c>='0' && c<='9')	x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
	return x;
}
void write(LL x)
{
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
LL a[100005],n;
void Solve()
{
	n=read();
	for(LL i=1;i<=n;++i)	a[i]=read();
	for(LL i=1;i<=n;++i)	if(a[i])	goto fail;
	puts("0");
	return ;
	fail:;
	LL sum=0,maxn=0;
	for(LL i=1;i<=n;++i)	sum+=a[i],maxn=max(maxn,a[i]);
	if(maxn*2<=sum)	puts("1");
	else	write(maxn-(sum-maxn)),puts("");
}
int main(){
	LL T=read();
	while(T-->0)	Solve();
	return 0;
}

CF1648A Weird Sum

注意到每一维独立,分开算。

把每种颜色的某一维坐标摊开,求两两间距离。排序过后就是前缀和。

/*
他决定要“格”院子里的竹子。于是他搬了一条凳子坐在院子里,面对着竹子硬想了七天,结果因为头痛而宣告失败。
DONT NEVER AROUND . //
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
LL read()
{
	LL x=0;
	char c=getchar();
	while(c<'0' || c>'9')	c=getchar();
	while(c>='0' && c<='9')	x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
	return x;
}
void write(LL x)
{
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
vector<LL> C[100005][2];
LL n,m;
int main(){
	n=read(),m=read();
	for(LL i=1;i<=n;++i)	for(LL j=1;j<=m;++j)	{int c=read();C[c][0].push_back(i),C[c][1].push_back(j);}
	for(LL i=1;i<=100000;++i)	sort(C[i][0].begin(),C[i][0].end()),sort(C[i][1].begin(),C[i][1].end());
	LL ans=0;
	for(LL i=1;i<=100000;++i)
	{
		LL sum=0,cnt=0;
		for(auto v:C[i][0])	ans+=cnt*v-sum,++cnt,sum+=v;
		sum=0,cnt=0;
		for(auto v:C[i][1])	ans+=cnt*v-sum,++cnt,sum+=v;
	}
	write(ans);
	return 0;
}

CF1648B Integral Array

枚举 \(d=\left\lfloor \frac{x}{y} \right\rfloor\),将 \(a\) 去重,就可以 \(O(n \ln n)\) 暴力做了。

/*
他决定要“格”院子里的竹子。于是他搬了一条凳子坐在院子里,面对着竹子硬想了七天,结果因为头痛而宣告失败。
DONT NEVER AROUND . //
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
int read()
{
	int x=0;
	char c=getchar();
	while(c<'0' || c>'9')	c=getchar();
	while(c>='0' && c<='9')	x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
	return x;
}
void write(int x)
{
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
inline int lowbit(int x){return x&(-x);}
int n,c,a[1000005];
int sum[2000005];
void Solve()
{
	n=read(),c=read();
	for(int i=1;i<=n;++i)	a[i]=read();
	sort(a+1,a+1+n);
	n=unique(a+1,a+1+n)-a-1;
	for(int i=1;i<=2*c;++i)	sum[i]=0;
	for(int i=1;i<=n;++i)	sum[a[i]]=1;
	for(int i=1;i<=2*c;++i)	sum[i]+=sum[i-1];
	for(int i=1;i<=c;++i)
	{
		if(sum[i]==sum[i-1])
		{
			for(int j=1;j*i<=c;++j)
			{
				if(sum[j]==sum[j-1])	continue;
				if(sum[j*(i+1)-1]^sum[i*j-1])
				{
					puts("No");
					return ;
				}
			}
		}
	}
	puts("Yes");
}
int main(){
	int T=read();
	while(T-->0)	Solve();
	return 0;
}

CF1648C Tyler and Strings

就纯粹傻逼 Samples & Pretests.

枚举两个字符串相同的前缀到哪儿,然后在这个位置填一个数 \(p\) 使得 \(p < t_i\),那么后面怎么填都是合法的;然后在这里填一个 \(q=t_i\),考虑下一个位置。

算答案的话,对于一个位置,先把所有 \(x \geq t_i\) 的填进没有填入的位置(不含当前位置)。选位置是组合数算,可重集计数要用线段树存一下值域算一下区间阶乘逆元积,用树状数组存某个值域区间里有多少数。小于 \(t_i\) 的数也是可重集计数。

然后有巨大多 Corner Case:

  1. 如果当前的所有数都小于 \(t_i\):算完滚蛋;
  2. 如果当前填不进一个等于 \(t_i\) 的数:滚蛋;
  3. 如果 \(n<m\),并且存在一种排列方式使得 \(s = \operatorname{pre}(t,|s|)\):答案加一(记得取模)。

就这样。傻逼题,数据还巨大多傻逼。纯粹傻逼。

/*
他决定要“格”院子里的竹子。于是他搬了一条凳子坐在院子里,面对着竹子硬想了七天,结果因为头痛而宣告失败。
DONT NEVER AROUND . //
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
LL read()
{
	LL x=0;
	char c=getchar();
	while(c<'0' || c>'9')	c=getchar();
	while(c>='0' && c<='9')	x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
	return x;
}
void write(LL x)
{
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
const LL MOD=998244353;
inline LL Add(LL u,LL v){return u+v>=MOD?u+v-MOD:u+v;}
inline LL Sub(LL u,LL v){return u-v>=0?u-v:u-v+MOD;}
inline LL Mul(LL u,LL v){return u*v%MOD;}
LL QuickPow(LL x,LL p=MOD-2)
{
	if(p<0)	p+=MOD-1;
	LL ans=1,base=x;
	while(p)
	{
		if(p&1)	ans=Mul(ans,base);
		base=Mul(base,base);
		p>>=1;
	}
	return ans;
}
inline LL lowbit(LL x){return x&(-x);}
const LL UP=200000;
struct BIT{
	LL tr[200005];
	void clear(){for(LL i=0;i<=UP;++i)	tr[i]=0;}
	void modify(LL x,LL v){for(LL i=x;i<=UP;i+=lowbit(i))	tr[i]+=v;}
	LL query(LL x){LL ret=0;for(LL i=x;i;i^=lowbit(i))	ret+=tr[i];return ret;}
	LL query(LL l,LL r){if(l>r)	return 0;return query(r)-query(l-1);}
}bit;
LL fac[200005],ifac[200005];
inline LL C(LL n,LL m){return m<0 || n<m?0:Mul(fac[n],Mul(ifac[m],ifac[n-m]));}
LL n,m,s[200005],t[200005],app[200005];
#define lc(x) (x<<1)
#define rc(x) (lc(x)|1)
#define Mm LL mid=(l+r)>>1
LL mpl[800005];
void push_up(LL now){mpl[now]=Mul(mpl[lc(now)],mpl[rc(now)]);}
void build(LL l,LL r,LL now)
{
	if(l==r)
	{
		mpl[now]=ifac[app[l]];
		return ;
	}
	Mm;
	build(l,mid,lc(now)),build(mid+1,r,rc(now));
	push_up(now);
}
void modify(LL l,LL r,LL now,LL x,LL v)
{
	if(l==r)
	{
		mpl[now]=ifac[v];
		return ;
	}
	Mm;
	if(x<=mid)	modify(l,mid,lc(now),x,v);
	else	modify(mid+1,r,rc(now),x,v);
	push_up(now);
}
LL query(LL l,LL r,LL now,LL x,LL y)
{
	if(x>y)	return 0;
	if(x<=l && r<=y)	return mpl[now];
	Mm,ret=1;
	if(x<=mid)	ret=Mul(ret,query(l,mid,lc(now),x,y));
	if(mid<y)	ret=Mul(ret,query(mid+1,r,rc(now),x,y));
	return ret;
}
#undef lc
#undef rc
#undef Mm
int main(){
//	freopen("C.in","r",stdin);
//	freopen("C.out","w",stdout);
	fac[0]=1;
	for(LL i=1;i<=200000;++i)	fac[i]=Mul(fac[i-1],i);
	ifac[200000]=QuickPow(fac[200000]);
	for(LL i=199999;~i;--i)	ifac[i]=Mul(ifac[i+1],i+1);
	n=read(),m=read();
	for(LL i=1;i<=n;++i)	s[i]=read();
	for(LL i=1;i<=m;++i)	t[i]=read();
	sort(s+1,s+1+n);
	for(LL i=1;i<=n;++i)	bit.modify(s[i],1),++app[s[i]];
	build(1,UP,1);
	LL ans=0;
	for(LL i=1;i<=min(n,m);++i)
	{
		LL all(bit.query(1,t[i]));
		if(all)
		{
			LL st(bit.query(1,t[i]-1)),pp=bit.query(1,UP);
			if(st==pp)
			{
				ans=Add(ans,Mul(fac[n-i+1],query(1,UP,1,1,UP)));
				goto haha;
			}
			else
			{
				pp-=st;
				ans=Add(ans,Mul(Mul(C(n-i,pp),Mul(fac[pp],query(1,UP,1,t[i],UP))),Mul(fac[st],query(1,UP,1,1,t[i]-1))));
				if(all==st)	goto haha;
				--app[t[i]];
				bit.modify(t[i],-1);
				modify(1,UP,1,t[i],app[t[i]]);
			}
		}
		else	goto haha;
	}
	if(n<m)	ans=Add(ans,1);
	haha:;
	write(ans);
	return 0;
}

CF1648D Serious Business

定义 \(dp_i\) 为最终停在 \((2,i)\) 的最大值。那么答案就是枚举 \(i\),算 \((2,i) \to (3,i) \to (3,n)\) 的最大值。

如何算 \(dp_i\) 呢?对于一个区间 \([l,r]\) 里的 \(i\),我们可以从 \(l-1\) 走进来,也可以从某个 \(j \in [l,i]\) 走过来。

转移式子的话,第一种情况是:\(dp_i = dp_{l-1} + suf_{2,l} - suf_{2,i+1} - k\),第二种情况是 \(dp_i = pre_{1,j} + suf_{2,j} - suf_{2,i+1} - k\),其中 \(pre,suf\) 分别表示前缀/后缀,第一个数表示行号。可以提出共同的只跟 \(i\) 有关的 \(-suf_{2,i+1}\)

第一种情况的话,我们将每个区间用左端点排序。这样相当于区间打 \(\max\) 的标记。求单点最大值,可以采用标记永久化。

第二种情况,左子树会影响右子树。每个结点转移类似,可以直接打标记。

看代码吧。

/*
他决定要“格”院子里的竹子。于是他搬了一条凳子坐在院子里,面对着竹子硬想了七天,结果因为头痛而宣告失败。
DONT NEVER AROUND . //
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
LL read()
{
	LL x=0,f=1;
	char c=getchar();
	while(c<'0' || c>'9')	f=(c=='-'?-1:f),c=getchar();
	while(c>='0' && c<='9')	x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
	return x*f;
}
void write(LL x)
{
	if(x<0)	putchar('-'),x=-x;
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
LL n,q,a[4][500005],sum1[500005],sum2[500005],sum3[500005];
#define lc(x) (x<<1)
#define rc(x) (lc(x)|1)
#define Mm LL mid=(l+r)>>1
LL tr[2000005],tag[2000005],maxn[2000005];
void build(LL l,LL r,LL now)
{
	tr[now]=-1e18,tag[now]=1e18;
	if(l==r)	return void(maxn[now]=sum1[l]+sum2[l]);
	Mm;
	build(l,mid,lc(now)),build(mid+1,r,rc(now));
	maxn[now]=max(maxn[lc(now)],maxn[rc(now)]);
}
inline void push_down(LL now){if(tag[now]!=1e18)	tr[rc(now)]=max(tr[rc(now)],maxn[lc(now)]-tag[now]),tag[lc(now)]=min(tag[lc(now)],tag[now]),tag[rc(now)]=min(tag[rc(now)],tag[now]);}
void modify(LL l,LL r,LL now,LL x,LL y,LL v)
{
	if(x<=l && r<=y)
	{
		tr[now]=max(tr[now],v);
		return ;
	}
	push_down(now);
	Mm;
	if(x<=mid)	modify(l,mid,lc(now),x,y,v);
	if(mid<y)	modify(mid+1,r,rc(now),x,y,v);
}
void modify(LL l,LL r,LL now,LL x,LL y,LL k,LL &mxn)
{
	if(x<=l && r<=y)
	{
		tr[now]=max(tr[now],mxn-k);
		tag[now]=min(tag[now],k);
		mxn=max(mxn,maxn[now]);
		return ;
	}
	push_down(now);
	Mm;
	if(x<=mid)	modify(l,mid,lc(now),x,y,k,mxn);
	if(mid<y)	modify(mid+1,r,rc(now),x,y,k,mxn);
}
LL query(LL l,LL r,LL now,LL x)
{
	if(l==r)	return max(tr[now],maxn[now]-tag[now]);
	push_down(now);
	Mm,ret=tr[now];
	if(x<=mid)	ret=max(query(l,mid,lc(now),x),ret);
	else	ret=max(query(mid+1,r,rc(now),x),ret);
	return ret;
}
#undef lc
#undef rc
#undef Mm
vector<pair<LL,LL>> G[500005];
#define mp make_pair
LL dp[500005];
int main(){
	n=read(),q=read();
	for(LL i=1;i<=3;++i)	for(LL j=1;j<=n;++j)	a[i][j]=read();
	#define A a[1]
	#define B a[2]
	#define C a[3]
	for(LL i=1;i<=n;++i)	sum1[i]=sum1[i-1]+A[i];
	for(LL i=n;i;--i)	sum2[i]=sum2[i+1]+B[i];
	for(LL i=n;i;--i)	sum3[i]=sum3[i+1]+C[i];
	#undef A
	#undef B
	#undef C
	build(1,n,1);
	for(LL i=1;i<=q;++i)
	{
		LL l=read(),r=read(),k=read();
		G[l].push_back(mp(r,k));
	}
	dp[0]=-1e18;
	LL L=0,ans=-1e18;
	for(LL i=1;i<=n;++i)
	{
		while(L<i-1)	++L,dp[L]=query(1,n,1,L)-sum2[L+1],ans=max(ans,dp[L]+sum3[L]);
		for(auto st:G[i])
		{
			LL r=st.first,w=st.second;
			modify(1,n,1,i,r,dp[i-1]+sum2[i]-w);
			LL mxn=-1e18;
			modify(1,n,1,i,r,w,mxn);
		}
	}
	while(L<=n-1)	++L,dp[L]=query(1,n,1,L)-sum2[L+1],ans=max(ans,dp[L]+sum3[L]);
	write(ans);
	return 0;
}
posted @ 2022-03-07 17:43  SyadouHayami  阅读(46)  评论(0编辑  收藏  举报

My Castle Town.