1. 程式人生 > >Atcoder AGC016 簡要題解

Atcoder AGC016 簡要題解

傳送門

+/- Rectangle

對於 ( x , y ) (x,y) ,若 x

  m o d   h ̸ = 0
x \bmod h \not = 0
或者 y   m o d   w ̸
= 0 y \bmod w \not = 0
那麼填 v v ,否則填 h w v 1 h*w*v-1 ,這樣列出等式後把 v v 選一個最大的就行了, 1 0 9 10^9 的範圍夠了。

#include <bits/stdc++.h>
using namespace std;
 
const double eps=1e-7;
int H,h,W,w;
inline int val(int i,int j,int a,int b) {return ((i%h)||(j%w)) ? a : b;}
int main() {
	cin>>H>>W>>h>>w;
	if((!(H%h)) && (!(W%w))) return puts("No"),0;
	int v=(1e9-1)/(h*w-1);
	if((long long)v*(H*W-(H/h)*h*(W/w)*w)<=((H/h)*(W/w))) return puts("No"),0;
	puts("Yes");
	for(int i=1;i<=H;i++,cout<<'\n')
		for(int j=1;j<=W;cout<<val(i,j,v,-v*(h*w-1)-1)<<' ',j++);
}

XOR Replace

設異或和為 x x 並放在 a n + 1 a_{n+1} ,發現操作就是交換 a i , a n + 1 a_i,a_{n+1} ,如果這樣做之後序列和 b b 不一樣那麼肯定無解。否則對於那些不相等的地方,找出一個置換,方案數為置換大小+1(因為第一步要和 n + 1 n+1 先交換),然後發現如果兩個置換某個數相等那麼兩個置換可以合併,於是用個並查集就行了。

#include <bits/stdc++.h>
using namespace std;
typedef pair <int,int> pii;
const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}
 
const int N=1e5+50;
int n,a[N],b[N],step;
int anc[N],vis[N];
map <int,int> s;
set <int> pos[N];
inline void lsh(int *c) {
	vector <int> vec;
	for(int i=1;i<=n+1;i++) vec.push_back(c[i]);
	sort(vec.begin(),vec.end());
	vec.erase(unique(vec.begin(),vec.end()),vec.end());
	for(int i=1;i<=n+1;i++) c[i]=lower_bound(vec.begin(),vec.end(),c[i])-vec.begin()+1; 
} 
inline int ga(int x) {return (anc[x]==x) ? x : (anc[x]=ga(anc[x]));}
inline void merge(int x,int y) {anc[ga(x)]=ga(y);}
int main() {
	n=rd();
	for(int i=1;i<=n;i++) a[i]=rd(), a[n+1]^=a[i], ++s[a[i]]; ++s[a[n+1]];
	for(int i=1;i<=n;i++) b[i]=rd(), b[n+1]^=b[i], --s[b[i]]; --s[b[n+1]];
	for(auto v:s) if(v.second) return puts("-1"),0;
	lsh(a); lsh(b); int m=*max_element(a+1,a+n+2);
	for(int i=1;i<=n+1;i++) 
		if((a[i]^b[i]) || i>n) pos[a[i]].insert(i);
	for(int i=1;i<=m;i++) anc[i]=i;
	for(int i=n+1;i;i--) if(i>n || (a[i]^b[i])){
		if(vis[i]) continue;
		vector <int> vec; 
		for(int j=b[i];;) {
			int nxt=*pos[j].begin();
			pos[j].erase(pos[j].begin());
			vec.push_back(nxt);
			if(nxt==i) break;
			else j=b[nxt];
		}
		for(auto j:vec) merge(b[j],b[i]), vis[j]=1; 
	}
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n+1;i++) if(a[i]^b[i] || i==n+1) {
		if(i<=n) ++step;
		if(!vis[ga(a[i])] && (ga(a[i])==a[i])) vis[ga(a[i])]=1, ++step;
	}
	cout<<step-1<<'\n';
}

Poor Turkeys

傻逼題,不斷維護 ( x , y ) (x,y) 表示不能同時存在的對就可以了。

#include <bits/stdc++.h>
using namespace std;
 
const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}
 
const int N=4e2+5;
 
int n,m;
bitset <N> sta[N],ban;
int main() {
	n=rd(), m=rd();
	for(int i=1;i<=m;i++) {
		int x=rd(), y=rd();
		sta[x]|=sta[y];
		sta[y]|=sta[x];
		for(int j=1;j<=n;j++) {
			int tag1=sta[j].test(x), tag2=sta[j].test(y);
			if(tag1) sta[j].set(y);
			if(tag2) sta[j].set(x);
		}
		sta[x].set(y); sta[y].set(x);
	}
	for(int i=1;i<=n;i++) 
		if(sta[i][i]) ban[i]=1;
	int cnt=0;
	for(int i=1;i<=n;i++) if(!ban[i]) {
		bitset <N> tp=sta[i];
		for(int j=1;j<=n;j++) tp.flip(j);
		cnt+=tp.count();
		tp&=ban