Codeforces Round #639 (Div. 2)划水记

u n r a t e d s o l v e   j u s t   f o r   f u n ? 好不爽\rightarrow unrated\rightarrow solve~ just~ for~ fun?

A A

题意:拼图,每块拼图部件有一个凹三个凸,只有凹凸可以贴合.问能否拼成 n m n*m 的图.

每个点有1个出度,3个入度.(边界的点看作对外有出度)

那么 n = 1 m = 1 n=1\cup m=1 一定可以.

n = m = 2 n=m=2 ,由样例得可行.

对于其他情况一定包含一个 2 3 3 2 2*3或3*2 的矩阵.

而这个矩阵内有7个相接的地方,由于每个相接的地方都有有凹,但实际上6<7,所以无论如何都不行.

int T,n,m; 

int main() {
	qr(T); while(T--) {
		qr(n); qr(m);
		if(n==m&&n==2) puts("yes");
		else if(min(n,m)==1) puts("yes");
		else puts("no");
	}
	return 0;
}

B B

容易看出一个DP转移函数:

f [ i ] f[i] 表示高度为 i i 要多少张牌.

{ f [ 0 ] = 0 , f [ 1 ] = 1 f [ i ] = 2 f [ i 1 ] f [ i 2 ] + 3 ( i > 1 ) \begin{cases}f[0]=0,f[1]=1\\f[i]=2f[i-1]-f[i-2]+3(i>1)\end{cases}

打表找到上界 i i ,然后每次用二分来查数即可.

int T,n,ans;
ll f[N];

void dfs(int x) {
	while(x>=2) {
		x-=(*(upper_bound(f+1,f+N,x)-1));
		ans++;
	}
}

int main() {
	f[1]=2;for(int i=2;i<N;i++) f[i]=2*f[i-1]-f[i-2]+3;
	qr(T);while(T--) {
		ans=0; qr(n);
		dfs(n); pr2(ans);
	}
	return 0;
}

更快的做法:

可以发现 f [ n ] = 1.5 n 2 + 0.5 n f[n]=1.5*n^2+0.5n

解方程即可.

C C

一开始题目看不懂,QAQ…

题意:给你 n n 个整数 a 0 , a 1 . . . . a n 1 a_0,a_1....a_{n-1} ,判断是否不存在 i j i + a [ i m o d    n ] = j + a [ j m o d    n ] i\ne j且i+a[i\mod n]=j+a[j\mod n] .

首先对于一个同余系的数一定不会冲突.

然后我们枚举 i , j ( 0 i < j < n ) i,j(0\le i<j<n) ,判断是否

i + a [ i ] j + a [ j ] ( m o d    n ) i+a[i]\equiv j+a[j](\mod n)

开个bool数组判断 ( i + a [ i ] ) m o d    n (i+a[i])\mod n 是否互不相同即可.

int T,n,a[N],ans,vis[N],num; 

int main() {
	qr(T); while(T--) {
		qr(n);for(int i=0;i<n;i++) qr(a[i]);
		ans=0; num++;
		for(int i=0,x;i<n;i++) {
			x=(i+a[i]%n+n)%n;
			if(vis[x]==num) {puts("No");ans=1;break;}
			else vis[x]=num;
		}
		if(!ans) puts("YES");
	}
	return 0;
}

D D

题意:

给定 n m n*m 的颜色(黑白)矩阵.开始随意放置S/N极.

之后当一对S,N极共享一个行/列,且不在同一个位置时,N往S靠近一个单位.

这个初始放置必须在随意移动后满足:

  • S极出现在每一行,每一列.
  • N极可以到达所有的黑格.
  • N极无法到达所有的白格.

求初始放置的最少N极数.

引理:

  • 每行/列只能有一段黑.
  • 一行无黑必须保证有列也无黑.

判定完不合法的情况后,只需计算黑色连通块数即可.

int n,m,v[N][N],cnt;
bool r[N],c[N];
char s[N][N];

void out(){puts("-1"),exit(0);}

const int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
void dfs(int x,int y) {
	v[x][y]=cnt;
	for(int t=0;t<4;t++) {
		int tx=x+dx[t],ty=y+dy[t];
		if(s[tx][ty]=='#'&&!v[tx][ty]) dfs(tx,ty);
	}
} 

int main() {
	qr(n);qr(m); 
	//每行/列至多有一段黑. 
	for(int i=1;i<=n;i++) {
		scanf("%s",s[i]+1);
		for(int j=1,k=0;j<=m;j++) 
			if(s[i][j]=='#') {
				r[i]=c[j]=1;
				if(s[i][j]!=s[i][j-1]) {
					if(++k>=2) out();
				}
			}
	}
	for(int j=1;j<=m;j++) 
		for(int i=1,k=0;i<=n;i++) 
			if(s[i][j]=='#') {
				r[i]=c[j]=1;
				if(s[i][j]!=s[i-1][j]) {
					if(++k>=2) out();
				}
			}
	//每行每列都要有S极 
	int a=0,b=0;
	for(int i=1;i<=n;i++) a+=!r[i];
	for(int j=1;j<=m;j++) b+=!c[j];
	if(a^b&&(!a||!b)) out();
	//接下来,每个黑色连通块都放一个N极. 
	for(int i=1;i<=n;i++) 
		for(int j=1;j<=m;j++) if(s[i][j]=='#'&&!v[i][j]) cnt++,dfs(i,j);
	pr2(cnt); 
	return 0;
}

实际可用并查集来合并行列(因为每行/列至多有一段).

E E

题目好绕,对我很不友好.

: n x 1 , x 2 . . . x n , m ( x a j < x b j , j [ 1 , m ] ) , 简明题意:有n个变量x_1,x_2...x_n,m条相互关系(x_{a_j}<x_{b_j},j\in[1,m]),设 f ( x ) = j = 1 m x a j < x b j ( a n d ) ) , Q 1 x 1 , Q 2 x 2 . . Q n x n f ( x ) = t r u e , Q i = / f(x)=\cap_{j=1}^m x_{a_j}<x_{b_j}(\cap指的是and运算)),最后的令Q1x_1,Q2x_2..Qnx_n f(x)=true,Qi=\forall /\exist

最后,求满足条件的最多的 \forall 数量

我们把相互关系看作 ( a j , b j ) (a_j,b_j) ,即一条有向边.

则显然,如果成环则无论如何都不合法,输出 1. ( x < x ) -1.(x<x)

然后,任意两个有大小关系的数至多有一个 \forall .

所以我们用拓扑判环+正反向DP即可.

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define gc getchar()
using namespace std;
const int N=2e5+10; 

void qr(int &x) {
	char c=gc; x=0;
	while(!isdigit(c))c=gc;
	while(isdigit(c))x=x*10+c-'0',c=gc;
}

int n,m,f[N],g[N],ans,q[N];
struct edge{int y,next;}a[N]; int len,last[N],deg[N];
void ins(int x,int y) {a[++len]=(edge){y,last[x]};last[x]=len;deg[y]++;}

void topsort() {
	int l=1,r=0;
	for(int i=1;i<=n;i++) if(!deg[i]) q[++r]=i;
	while(l<=r) {
		int x=q[l++];
		for(int k=last[x],y;k;k=a[k].next) {
			y=a[k].y;
			f[y]=min(f[x],f[y]);
			if(!(--deg[y])) q[++r]=y;
		}
	}
	if(r<n) puts("-1"),exit(0);
	while(r) {
		int x=q[r--];
		for(int k=last[x],y;k;k=a[k].next) {
			y=a[k].y;
			g[x]=min(g[x],g[y]);
		}
	}
}

int main() {
	qr(n); qr(m);
	for(int i=1;i<=n;i++) f[i]=g[i]=i;
	for(int i=1,x,y;i<=m;i++) {
		qr(x),qr(y);
		ins(x,y);
	}
	topsort();
	for(int i=1;i<=n;i++) f[i]=min(f[i],g[i]),ans+=(f[i]==i);
	printf("%d\n",ans);
	for(int i=1;i<=n;i++) putchar("EA"[f[i]==i]);
	return 0;
}
//有环一定不合法.
//然后对于任意有大小关系的变量之间只能有一个forall.
//于是,对每个点求跟其大小相关的点的最小值. 
//做法:用拓扑排序判环/正反向DP. 

F F

定义二元函数 f ( x , y ) = x ( y x 2 ) f(x,y)=x(y-x^2)

我们考虑增量法:把x-1弄到x-> Δ = f ( x , a [ i ] ) f ( x 1 , a [ i ] ) = a 1 3 x ( x 1 ) \Delta =f(x,a[i])-f(x-1,a[i])=a-1-3x(x-1) .

显然这是一个当 x 1 x\ge 1 时递减的函数.

一个贪心的做法是每次取最大的变化量,复杂度 O ( k n ) O(kn) ,配合堆优化可 O ( k log n ) O(k\log n)

但是k太大了,不能直接处理.

我们要利用到增量的递减性质.

由贪心思路得:每次选择的变化量不严格递减.

所以,如果我们确定最后一个变化量,即可求出最多变化多少次.这个考虑二分处理: l = min i = 1 n f ( a [ i ] , a [ i ] ) , r = max i = 1 n f ( 1 , a [ i ] ) l=\min_{i=1}^n f(a[i],a[i]),r=\max_{i=1}^n f(1,a[i])

最后还剩下至多 n n 个数可选择,对还能选择的量进行排序贪心选大的即可.

ps:对于每个 a i a_i ,求最多增加几次的时候可二分可用解二次方程的方法

复杂度: O ( n log ( r l ) log m a x a i ) O(n\log (r-l)\log maxai)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<functional>
#define pi pair<ll,int>
#define ll long long
using namespace std;
const int N=1e5+10; 

int n,b[N];
ll m,a[N],tot;
pi s[N];int cnt;

ll f(ll x,ll y) {return y-1-3*x*(x-1);}
int calc(ll x,ll t) {//x为a[i],t为delta的下界 .找第一个<t的位置 
	int l=1,r=x+1,mid;
	while(l<r) {
		mid=l+r>>1;
		if(f(mid,x)<t) r=mid;
		else l=mid+1;
	}
	return l-1;
}
bool check(ll x) {
	tot=0;
	for(int i=1;i<=n&&tot<=m;i++) tot+=(b[i]=calc(a[i],x));
	return tot<=m;
}

int main() {
	scanf("%d %lld",&n,&m);
	ll l=9e18,r=0,mid;
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]),r=max(r,f(1,a[i])),l=min(l,f(a[i],a[i]));
	while(l<r) {
		mid=l+r>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	check(l); 
	m=m-tot;
	if(m) for(int i=1;i<=n;i++) 
		if(b[i]<a[i])
			s[++cnt]=make_pair(f(b[i]+1,a[i]),i);
	sort(s+1,s+cnt+1,greater<pi>());
	for(int i=1;i<=m;i++) b[s[i].second]++;
	for(int i=1;i<=n;i++) printf("%d ",b[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42886072/article/details/105978599
今日推荐