+/- Rectangle
对于 ( x , y ) (x,y) (x,y),若 x   m o d   h ̸ = 0 x \bmod h \not = 0 xmodh̸=0或者 y   m o d   w ̸ = 0 y \bmod w \not = 0 ymodw̸=0那么填 v v v,否则填 h ∗ w ∗ v − 1 h*w*v-1 h∗w∗v−1,这样列出等式后把 v v v选一个最大的就行了, 1 0 9 10^9 109的范围够了。
#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 x并放在 a n + 1 a_{n+1} an+1,发现操作就是交换 a i , a n + 1 a_i,a_{n+1} ai,an+1,如果这样做之后序列和 b b b不一样那么肯定无解。否则对于那些不相等的地方,找出一个置换,方案数为置换大小+1(因为第一步要和 n + 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) (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;
cnt-=tp.count();
} cout<<(cnt-(n-ban.count()))/2<<'\n';
}
Games on DAG
感觉这场最难的是D题。
一个方案先手必胜,一定时 s g 1 ̸ = s g 2 sg_1 \not = sg_2 sg1̸=sg2,于是从小到大依次确定 s g sg sg值,保证转移的时候 s g sg sg大的到小的一定有连边,小的到大的随便连就行了。
#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=17, mod=1e9+7;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int mul(int x,int y) {return (long long)x*y%mod;}
inline int pct(int x) {return __builtin_popcount(x);}
int n,m,g[N],bin[N],f[1<<N];
inline int valid(int s1,int al) {
if((s1&1) && (s1&2)) return 0;
int s2=(bin[n]-1)^al, sum=1;
for(int j=0;j<n;j++) if(s2&bin[j]) {
if(!(s1&g[j])) return 0;
int c=pct(s1&g[j]);
sum=mul(sum,bin[c]-1);
}
for(int j=0;j<n;j++) if(s1&bin[j]) {
int c=pct(s2&g[j]);
sum=mul(sum,bin[c]);
}
return sum;
}
int main() {
n=rd(), m=rd();
for(int i=0;i<=n;i++) bin[i]=1<<i;
for(int i=1;i<=m;i++) {
int x=rd()-1, y=rd()-1;
g[x]|=bin[y];
}
f[0]=1;
for(int s=1;s<bin[n];++s) {
for(int s2=s;s2;s2=(s2-1)&s) {
int t=valid(s2,s);
if(t) f[s]=add(f[s],mul(f[s^s2],t));
}
}
cout<<f[bin[n]-1]<<'\n';
}