【学习笔记】AGC059

蓝题都不会做

agc059

My Last ABC Problem

首先一次操作显然最多可以让相邻不同元素对 − 2 -2 2

考虑选取 A A A作为特征元素,那么会分成若干段 B C BC BC交错的区间,如果长度为奇数那么可以先全部变成 B / C B/C B/C再翻过来;如果长度为偶数那么可以看成长度为 2 2 2的段。对于两个长度为 2 2 2的段可以合并在一起,最后如果剩的长度为 4 4 4就再操作 2 2 2次即可。

基于上述观察,我们在询问区间的开头和结尾添一个字母(表示整个区间最终变成的结果),设此时序列长度为 L L L,那么 ⌈ L − 1 2 ⌉ \lceil\frac{L-1}{2}\rceil 2L1就是答案。

#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
int n,m;
int a[100005],p[100005],cnt;
string s;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>m>>s;
	for(int i=0;i<s.size();i++){
		int j=i;while(j+1<s.size()&&s[j+1]==s[i])j++;
		i=j,a[++cnt]=s[i]-'A',p[cnt]=j+1;
	}
	for(int i=1;i<=m;i++){
		int l,r;cin>>l>>r,l=lower_bound(p+1,p+1+cnt,l)-p,r=lower_bound(p+1,p+1+cnt,r)-p;
		if(l==r)cout<<0<<"\n";
		else {
			if(a[l]==a[r])cout<<(r-l+1)/2<<"\n";
			else cout<<(r-l+2)/2<<"\n";
		}
	}
}

Arrange Your Balls

2 hard 4 me

一个简单的思路是,首先把相同颜色的球排在一起,这样答案是颜色数目 k k k

如果一个颜色段很小,那么可以合并到大的颜色块当中,并且只占一个间隙。

基于上述观察,我们可以贪心的取出任意一个颜色块,然后将其他颜色块插入到它的一个间隙中(这个颜色产生的贡献恰为 1 1 1),这样如果最后剩的颜色块数目 ≤ 2 \le 2 2那么答案是 k − 1 k-1 k1

模拟即可。

#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
int T,n,r,id[200005],c[200005],nxt[200005],vis[200005],res[200005];
int cnt,cnt2;
pair<int,int>s[200005],s2[200005];
int main(){
//	freopen("data.in","r",stdin);
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>T;
	while(T--){
		cin>>n;for(int i=1;i<=n;i++)c[i]=nxt[i]=vis[i]=0;
		for(int i=1;i<=n;i++){
			int x;cin>>x,c[x]++;
		}r=cnt=cnt2=0;
		for(int i=1;i<=n;i++){
			if(!c[i])continue;
			for(int j=1;j<=c[i];j++)id[j]=++r,res[r]=i;
			for(int j=1;j<c[i];j++)nxt[id[j]]=id[j+1];
			if(c[i]>1){
				for(int j=1;j<c[i];j++){
					s[++cnt]={id[j],id[j+1]};
				}
				while(cnt2&&cnt){
					nxt[s[cnt].fi]=s2[cnt2].fi;
					nxt[s2[cnt2].se]=s[cnt].se;
					cnt2--,cnt--;
				}
				s2[++cnt2]={id[1],id[c[i]]};
			}
			else{
				if(cnt){
					nxt[s[cnt].fi]=id[1],nxt[id[c[i]]]=s[cnt].se;
					cnt--;
				}
				else {
					s2[++cnt2]={id[1],id[c[i]]};
				}
			}
		}
		for(int i=1;i<cnt2;i++){
			nxt[s2[i].se]=s2[i+1].fi;
		}
		for(int i=1;i<=n;i++){
			vis[nxt[i]]=1;
		}
		int rt=0;
		for(int i=1;i<=n;i++){
			if(!vis[i])rt=i;
		}assert(rt);
		while(rt){
			cout<<res[rt]<<' ',rt=nxt[rt];
		}cout<<"\n";
	} 
}

Guessing Permutation for as Long as Possible

数数题令人头疼

可以把过程想象为在一张图上每次加一条有向边 ( u , v ) (u,v) (u,v),如果存在路径 u ′ → v ′ u'\to v' uv并且 ( u ′ , v ′ ) ≠ E (u',v')\ne E (u,v)=E那么就不合法。

然后考虑所有三元导出子图,如果 ( X , Y ) (X,Y) (X,Y), ( Y , Z ) (Y,Z) (Y,Z)的出现时刻比 ( X , Z ) (X,Z) (X,Z)早,并且满足 X > Y > Z X>Y>Z X>Y>Z,那么就可以确定出 X > Z X>Z X>Z,故而不合法。

直接数原排列 p p p复杂度 O ( 2 n ) O(2^n) O(2n)。既然原排列不好数,那么我们考虑每个原排列一定对应唯一一个完全图,其中每条边的颜色表示两个元素之间的大小关系。

那么我们考虑上述条件相当于 ( X , Y ) , ( Y , Z ) (X,Y),(Y,Z) (X,Y),(Y,Z)的颜色必须不同,那么我们构造一个含 n 2 n^2 n2个点的图,如果不存在二分图匹配那么答案是 0 0 0。否则对于一个连通图有两种染色方案,同时对于一个合法的染色方案,它所对应的图一定不存在环,因此存在拓扑排序,也就存在一个合法的 p p p。综上,我们只要数合法的染色方案即可,设连通块数目为 k k k,则总方案数为 2 k 2^k 2k

#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
const int mod=1e9+7;
int n,m,id[405][405],a[405][405];
int c[405*405];
vector<pair<int,int>>g[405*405];
void add(int x,int y,int z){
	g[x].pb({y,z}),g[y].pb({x,z});
}
void dfs(int u,int topf){
	c[u]=topf;
	for(auto v:g[u]){
		if(c[v.fi]==-1)dfs(v.fi,topf^v.se);
		else if(c[v.fi]!=(topf^v.se)){
			cout<<0;
			exit(0);
		}
	}
}
int main(){
//	freopen("data.in","r",stdin);
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			id[i][j]=id[j][i]=++m;
		}
	}
	for(int i=1;i<=m;i++){
		int x,y;cin>>x>>y,a[x][y]=a[y][x]=i;
	}
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			for(int k=j+1;k<=n;k++){
				if(a[j][i]<a[i][k]&&a[j][k]<a[i][k]){
					add(id[j][i],id[j][k],(i<j)^(j>k));
				}
				else if(a[k][i]<a[i][j]&&a[k][j]<a[i][j]){
					add(id[k][i],id[k][j],(i<k)^(k>j));
				}
				else if(a[i][j]<a[j][k]&&a[i][k]<a[j][k]){
					add(id[i][j],id[i][k],(j<i)^(i>k));
				}
			}
		}
	}memset(c,-1,sizeof c);ll res=1;
	for(int i=1;i<=m;i++){
		if(c[i]==-1){
			dfs(i,0),res=res*2%mod;
		}
	}cout<<res;
}

Grid 3-coloring

这个D实在是不可做啊

我们考虑构造一个与 c c c同余的矩阵 a a a,并且满足 a a a矩阵中相邻位置数字只差恰好为 1 1 1

容易发现,至少存在一个合法的 a a a矩阵与 c c c对应(考虑从左上角开始构造,容易验证不会产生矛盾),如果规定矩阵的数字最小的话那么不难猜想 a a a, c c c矩阵形成一一对应关系。

不妨假设 a 1 , 1 = c 1 , 1 a_{1,1}=c_{1,1} a1,1=c1,1,然后将 4 n − 4 4n-4 4n4个变量全部确定出来。如果存在矛盾那么显然无解。

然后我们得到了有解的必要条件:

1.1 1.1 1.1对于任意 2 ≤ i ≤ n − 1 2\le i\le n-1 2in1,满足 ∣ a i , 1 − a i , n ∣ < n |a_{i,1}-a_{i,n}|<n ai,1ai,n<n 并且 ∣ a 1 , i − a n , i ∣ < n |a_{1,i}-a_{n,i}|<n a1,ian,i<n

考虑给出构造或者直接走人 a i , j = max ⁡ ( { a i , 1 − ( j − 1 ) , a i , n − ( n − j ) , a 1 , j − ( i − 1 ) , a n , j − ( n − i ) } ) a_{i,j}=\max(\{a_{i,1}-(j-1),a_{i,n}-(n-j),a_{1,j}-(i-1),a_{n,j}-(n-i)\}) ai,j=max({ai,1(j1),ai,n(nj),a1,j(i1),an,j(ni)})

这个式子怎么来看呢,首先我们证明 ( n − 2 ) × ( n − 2 ) (n-2)\times (n-2) (n2)×(n2)矩阵中相邻位置的差恰好为 1 1 1

证明非常巧妙,考虑手玩样例,我们会发现 { a i , 1 − ( j − 1 ) , a i , n − ( n − j ) , a 1 , j − ( i − 1 ) , a n , j − ( n − i ) } \{a_{i,1}-(j-1),a_{i,n}-(n-j),a_{1,j}-(i-1),a_{n,j}-(n-i)\} {ai,1(j1),ai,n(nj),a1,j(i1),an,j(ni)}的奇偶性相同,那么相邻位置的每一项都相差 1 1 1,这样最大值相差最多是 1 1 1,又因为奇偶性不同,因此恰好相差 1 1 1

然后考虑边界的取值。假设 ∣ a i , 1 − a i , 2 ∣ ≠ 1 |a_{i,1}-a_{i,2}|\ne 1 ai,1ai,2=1(对于其他情况将矩形旋转即可),那么 a i , 2 ≥ a i , 1 + 3 a_{i,2}\ge a_{i,1}+3 ai,2ai,1+3,如果 a i , 2 = a i , n − ( n − 2 ) a_{i,2}=a_{i,n}-(n-2) ai,2=ai,n(n2)那么 a i , n = a i , 1 + 1 a_{i,n}=a_{i,1}+1 ai,n=ai,1+1与条件矛盾;如果 a i , 2 = a 1 , 2 − ( i − 1 ) a_{i,2}=a_{1,2}-(i-1) ai,2=a1,2(i1)那么 a 1 , 2 ≥ a i , 1 + i + 2 a_{1,2}\ge a_{i,1}+i+2 a1,2ai,1+i+2并且 a 1 , 1 ≤ a i , 1 + i − 1 a_{1,1}\le a_{i,1}+i-1 a1,1ai,1+i1,故而 ∣ a 1 , 2 − a 1 , 1 ∣ ≥ 3 |a_{1,2}-a_{1,1}|\ge 3 a1,2a1,13与条件矛盾;如果 a i , 2 = a n , 2 − ( n − i ) a_{i,2}=a_{n,2}-(n-i) ai,2=an,2(ni)那么证明类似。

综上,我们证明了上述构造的合法性。复杂度 O ( n ) O(n) O(n)

#include<bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
int T,n,a[1000005];
int b[1005][1005];
string s;
int solve(){
	cin>>n>>s;a[1]=s[0]-'0';
	for(int i=2;i<=4*n-4;i++){
	    a[i]=s[i-1]-'0';if(a[i]%3==a[i-1]%3)return 0;
		if((a[i-1]+1)%3==a[i]%3)a[i]=a[i-1]+1;
		else a[i]=a[i-1]-1;
	}
	if(abs(a[1]-a[4*n-4])!=1)return 0;
	for(int i=2,j=3*(n-1);i<n;i++,j--){
		if(abs(a[i]-a[j])>=n)return 0;
	}
	for(int i=n+1,j=4*n-4;i<2*n-1;i++,j--){
		if(abs(a[i]-a[j])>=n)return 0;
	}return 1;
}
void print(){
	for(int i=1;i<n;i++)b[1][i]=a[i];
	for(int i=1;i<n;i++)b[i][n]=a[i+n-1];
	for(int i=1;i<n;i++)b[n][n-i+1]=a[i+2*(n-1)];
	for(int i=1;i<n;i++)b[n-i+1][1]=a[i+3*(n-1)];
	for(int i=2;i<n;i++){
		for(int j=2;j<n;j++){
			b[i][j]=max({b[i][1]-(j-1),b[i][n]-(n-j),b[1][j]-(i-1),b[n][j]-(n-i)});
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cout<<b[i][j]<<' ';
		}cout<<"\n";
	}
}
int main(){
	freopen("data.in","r",stdin);
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>T;
	while(T--){
		cout<<(solve()?"YES":"NO")<<"\n";
		print();
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值