# 2016多校第一场

1002 chess

tag:博弈论 SG函数应用 状态压缩并记录

1：一个人可以选一个棋子移动到这个棋子右边的空位上

2：如果右边没有空位那么跳过右边的棋子移动到最近的空位上

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>

using namespace std;
int n;
int dp[(1<<20)+100];

int dfs(int st) {
if(dp[st] != -1) return dp[st];
bool ex[50] = {0};
for(int i=0; i<20; i++) {
if(((st>>i)&1) == 0) continue;
int j = i+1;
while(j<20 && ((st>>j)&1)==1) j++;
if(j < 20) {
int tp = st;
tp ^= (1<<i), tp ^= (1<<j);
int s = dfs(tp);
ex[s] = 1;
}
}
int sg = 0;
while(ex[sg]) sg++;
dp[st] = sg;
return sg;
}

int main() {
int T;
memset(dp, -1, sizeof(dp));
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
int SG = 0;
while(n--) {
int num; scanf("%d", &num);
int st = 0;
for(int i=0; i<num; i++) {
int t; scanf("%d", &t);
st |= (1<<(t-1));
}
SG ^= dfs(st);
}
if(SG) printf("YES\n");
else printf("NO\n");
}
return 0;
}

1004 gcd

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <map>

using namespace std;
const int maxn = 100000 + 100;
int N, M;
int a[maxn];
map<int, long long> mp;

int ST[maxn][20];
int gcd(int m, int n) {
if(n == 0) return m;
else return gcd(n, m%n);
}
void init() {
for(int i=1; i<=N; i++)
ST[i][0] = a[i];
for(int j=1; (1<<j)<=N; j++)
for(int i=1; i<=N; i++) {
ST[i][j] = ST[i][j-1];
if(i+(1<<(j-1)) > N) continue;
ST[i][j] = gcd(ST[i][j-1], ST[i+(1<<(j-1))][j-1]);
}
}
int query(int l, int r) {
int k = log((double)r-l+1)/log(2.0);
return gcd(ST[l][k], ST[r-(1<<k)+1][k]);
}

void getnum(int L, int g, int &r1, int &r2) {
int l = L, r = N;
while(l <= r) {
int mid = (l+r)/2;
int tp = query(L, mid);
if(tp == g) r1 = mid, r = mid-1;
else if(tp > g) l = mid + 1;
else r = mid - 1;
}
l = L, r = N;
while(l <= r) {
int mid = (l+r)/2;
int tp = query(L, mid);
if(tp == g) r2 = mid, l = mid + 1;
else if(tp > g) l = mid + 1;
else r = mid - 1;
}
}

void init2() {
mp.clear();
for(int l=1; l<=N; l++) {
int g = a[l];
while(1) {
int r1, r2;
getnum(l, g, r1, r2);
mp[g] += r2-r1+1;
if(r2 == N) break;
g = query(l, r2+1);
}
}
}

int main() {
int T;
scanf("%d", &T);
int kase = 0;
while(T--) {
scanf("%d", &N);
for(int i=1; i<=N; i++) scanf("%d", &a[i]);
init();
init2();
scanf("%d", &M);
printf("Case #%d:\n", ++kase);
for(int i=1; i<=M; i++) {
int l, r; scanf("%d%d", &l, &r);
printf("%d %lld\n", query(l, r), mp[query(l, r)]);
}
}
return 0;
}

//1
//5
//1 2 4 6 7
//4
//1 5
//2 4
//3 4
//4 4
//
//Case #1:
//1 8
//2 4
//2 4
//6 1


1005 necklace

tag:二分图匹配

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;
const int maxn = 100;
int V;    //顶点数
vector<int> G[maxn];
int match[maxn];
bool used[maxn];
void add_edge(int u, int v) {
//printf("u = %d, v = %d\n", u, v);
G[u].push_back(v);
G[v].push_back(u);
}

bool dfs(int v) {
used[v] = true;
for(int i=0; i<G[v].size(); i++) {
int u = G[v][i], w = match[u];
if(w<0 || (!used[w] && dfs(w))) {
match[v]  = u;
match[u] = v;
return true;
}
}
return false;
}

int bipartite_matching() {
int res = 0;
memset(match, -1, sizeof(match));
for(int v = 0; v<V; v++) {
if(match[v] < 0) {
memset(used, 0, sizeof(used));
if(dfs(v)) res++;
}
}
return res;
}

int N, M;  //N个珠子 M个限制条件
int a[maxn];
int conflict[maxn][maxn];

int main() {
while(~scanf("%d%d", &N, &M)) {    // 0 - N-1
memset(conflict, 0, sizeof(conflict));
for(int i=0; i<M; i++) {
int a, b; scanf("%d%d", &a, &b);
conflict[a-1][b-1] = 1;
}
for(int i=0; i<N; i++) a[i] = i;
int ans = 0x3f3f3f3f;
do {
//            for(int i=0; i<N; i++) printf("%d ", a[i]);
//            printf("\n");
for(int i=0; i<=2*N; i++) G[i].clear();
for(int ya=0; ya<N; ya++) {   //阳开始匹配
for(int yi=0; yi<N; yi++) {
int pre = (yi-1+N)%N, nxt = yi;
}
}
V = 2*N;
int res = bipartite_matching();
//printf("res = %d\n", res);
ans = min(ans, N-res);
if(ans == 0) break;
}while(next_permutation(a+1, a+N));
printf("%d\n", ans);
}
return 0;
}