Examples

2022-6-21 #2 CF1695E & ARC142F

今日份的博客!!!

专门鸽掉了 Binomial Sum 来更博,良心博主啊!

啊啊啊,最近越来越不想写代码了怎么办。

003 CF1695E Ambiguous Dominoes

遇到图论的题就不会做,怎么说!

下面通过构造来证明,除非问题无解,否则我们一定存在一种方法使得所有多米诺骨牌可以放在 \(2\times n\) 的矩形内。

我们对于一个多米诺骨牌,连接 \((x_i,y_i)\),那么一个连通块可以一起考虑。

对于一个连通块,我们搜出一个欧拉序(长度为二倍边数加一),我们去掉结尾,然后直接盘成一圈放在前面,可以发现从任意位置开始依次放置骨牌都是合法方案,那么第一个方案从 \(1\) 开始放,第二个方案从 \(2\) 开始放就好了。

复杂度 \(O(n+m)\)

#include<stdio.h>
#include<vector>
using namespace std;
const int maxn=300005;
int n,dfns;
int xx[maxn],yy[maxn],vise[maxn],dfn[maxn<<1],visp[maxn<<1],ans[2][maxn<<1],res[maxn<<1];
vector<int>v[maxn<<1];
void dfs(int x){
	dfn[++dfns]=x;
	if(visp[x])
		return ;
	visp[x]=1;
	while(!v[x].empty()){
		int k=v[x].back(),y=xx[k]+yy[k]-x;
		v[x].pop_back();
		if(vise[k])
			continue;
		vise[k]=1,dfs(y),dfn[++dfns]=x;
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1,x,y;i<=n;i++)
		scanf("%d%d",&x,&y),v[x].push_back(i),v[y].push_back(i),xx[i]=x,yy[i]=y;
	int L=1,R=n+1;
	for(int i=1;i<=n+n;i++)
		if(v[i].size()){
			dfs(i),dfns--;
			if(dfns==2){
				puts("-1");
				return 0;
			}
			int v=0;
			for(int j=1;j<=dfns/2;j++){
				res[L]=dfn[j];
				ans[0][L]=v==0? (j==dfns/2? 'U':'L'):'R';
				ans[1][L]=(j==1)? 'U':(v==1? (j==dfns/2? 'U':'L'):'R');
				L++,v^=1;
			}
			R+=dfns/2;
			for(int j=1;j<=dfns/2;j++){
				res[R-j]=dfn[dfns/2+j];
				ans[0][R-j]=v==1? (j==1? 'D':'L'):'R';
				ans[1][R-j]=(j==dfns/2)? 'D':(v==0? (j==1? 'D':'L'):'R');
				v^=1;
			}
			dfns=0;
		}
	printf("2 %d\n",n);
	for(int i=1;i<=n+n;i++)
		printf("%d%c",res[i],i%n==0? '\n':' ');
	for(int c=0;c<=1;c++)
		for(int i=1;i<=n+n;i++){
			putchar(ans[c][i]);
			if(i%n==0)
				putchar('\n');
		}
	return 0;
}

004 ARC142F Paired Wizards

感觉并不难想,但是很难!

首先要将造成的伤害用一个比较好的式子刻画出来,我们令 \(x_{1,2,\cdots,u}\) 表示第一个人的 2 操作序列,\(y_{1,2,\cdots,v}\) 类似,那么伤害就是:

\[\sum_{i=1}^u(x_i-i)+\sum_{i=1}^v(y_i-i) \]

也就是说,造成的伤害只与选择的 2 操作下标和,第一个人 2 操作数量,第二个人操作数量有关。

把给定的操作分为四类:

  • 两个人的操作都固定;
  • 一个人固定,一个人不固定;(分别称为 A,B)
  • 1122 形(称为 C)
  • 1221 形(称为 D)

首先预处理出 \(f_i\) 表示第一个人选定了 \(i\) 个非 A 的 2 操作后,使用 A 能带来多少收益,\(g_i\) 同理。

选择的一定是一个后缀,所以我们可以对于一个 \(i\) \(O(n)\) 计算 \(f,g\)

发现 C 选择的一定是一个后缀,发现 D 造成的下标和贡献是固定的,所以我们可以单纯地枚举使用了多少个 C,以及使用了多少个 D 给第一个人,利用 \(f,g\) 可以 \(O(1)\) 计算答案。

复杂度 \(O(n^2)\)

#include<stdio.h>
const int maxn=8005;
int n,x,y,sx,sy,tot,sum,ans;
int typ[maxn],f[maxn],g[maxn];
inline int max(int a,int b){
	return a>b? a:b;
}
int main(){
	scanf("%d",&n);
	for(int i=1,a,b,c,d;i<=n;i++){
		scanf("%d%d%d%d",&a,&b,&c,&d);
		if(a==c||b==d){
			if(a==c){
				if(a==2)
					x++,sx+=i;
				if(b!=d)
					typ[i]=2;
			}
			if(b==d){
				if(b==2)
					y++,sy+=i;
				if(a!=c)
					typ[i]=1;
			}
		}
		else{
			if(a==b)
				typ[i]=3;
			else tot++,sum+=i;
		}
	}
	for(int i=0;i<=n;i++){
		f[i]=-i*(i+1)/2;
		for(int j=n,t=i,s=-i*(i+1)/2;j>=1;j--)
			if(typ[j]==1)
				t++,s+=j-t,f[i]=max(f[i],s);
	}
	for(int i=0;i<=n;i++){
		g[i]=-i*(i+1)/2;
		for(int j=n,t=i,s=-i*(i+1)/2;j>=1;j--)
			if(typ[j]==2)
				t++,s+=j-t,g[i]=max(g[i],s);
	}
	ans=-1e9;
	for(int i=0;i<=tot;i++){
		int t=0,s=0;
		ans=max(ans,f[x+i]+g[y+(tot-i)]);
		for(int j=n;j>=1;j--)
			if(typ[j]==3)
				t++,s+=j+j,ans=max(ans,f[x+t+i]+g[y+t+(tot-i)]+s);
	}
	printf("%d\n",ans+sx+sy+sum);
	return 0;
}
posted @ 2022-06-21 19:44  xiaoziyao  阅读(106)  评论(1)    收藏  举报