A
很容易可以想到 所以每个位置 都应该等于 ,然后再判断前 个如果是确定的 或者 ,有没有超过 就可以了
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define MP make_pair
#define fi first
#define se second
#define PB push_back
#define CL clear
#define pii pair<int,int>
#define int long long
using namespace std;
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int N = (int)(3e5) + 10;
const int mod = 1e9+7;
const int inf = 1e9 + 10;
const long double pi = acos(-1);
inline int rd() {
int p=0; int f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
char s[N];
int fa[N],siz[N]; int find(int x){return (fa[x] == x) ? fa[x] : fa[x] = find(fa[x]);}
signed main() {
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
int t = rd();
while(t--) {
int n = rd(); int m = rd();
scanf("%s",s+1);
for(int i=1;i<=n+2;i++) fa[i] = i;
for(int i=1;i<=n;i++) {
if(s[i] == '0') {
int x = find(i); int y = find(n+1);
if(x!=y) fa[x] = y;
}else if(s[i] == '1') {
int x = find(i); int y = find(n+2);
if(x!=y) fa[x] = y;
}
if(i + m <= n) {
int x = find(i); int y = find(i+m);
if(x!=y) fa[x] = y;
}
if(i - m > 0) {
int x = find(i); int y = find(i-m);
if(x!=y) fa[x] = y;
}
}
if(find(n+1) == find(n+2)) puts("NO");
else {
bool bk = 1;
int s0 = 0; int s1 = 0;
for(int i=1;i<=n;i++) {
if(find(i) == find(n+1)) s0++;
if(find(i) == find(n+2)) s1++;
if(i>m) {
if(find(i-m) == find(n+1)) s0--;
if(find(i-m) == find(n+2)) s1--;
}
if(s0 > m/2 || s1 > m/2){bk = 0; break;}
}
if(bk) puts("YES");
else puts("NO");
}
}
return 0;
}
B
首先如果要Bob赢可以想到三个结论,假设树的直径为
:
不然的话Alice先跳到树的重心就一定能抓到Bob
这个是因为如果Alice和Bob的距离是
,Bob必须要跳到距离Alice
的地方
满足这两个条件,如果当前是Bob跳的话,Bob是一定能跳到距离Alice
的地方,因为Bob肯定可以跳到直径上距离Alice比较远的地方(这个需要脑补一下证明)
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define MP make_pair
#define fi first
#define se second
#define PB push_back
#define CL clear
#define pii pair<int,int>
#define int long long
using namespace std;
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int N = (int)(1e5) + 10;
const int mod = 1e9+7;
const int inf = 1e9 + 10;
const long double pi = acos(-1);
inline int rd() {
int p=0; int f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
struct node{int x,y,nex;}edge[N<<1]; int len,fir[N];
void ins(int x,int y){len++; edge[len].x=x; edge[len].y=y; edge[len].nex = fir[x]; fir[x] = len;}
int n,a,b,da,db;
int dep[N];
void dfs(int x,int f) {
for(int k=fir[x];k!=-1;k=edge[k].nex) {
int y = edge[k].y;
if(y==f) continue;
dep[y] = dep[x] + 1; dfs(y,x);
}
}
signed main(){
int t = rd();
while(t--) {
n = rd(); a = rd(); b = rd(); da = rd(); db = rd();
len = 0; for(int i=1;i<=n;i++) fir[i] = -1;
for(int i=1;i<n;i++) {
int x = rd(); int y = rd();
ins(x,y); ins(y,x);
}
dep[a] = 0; dfs(a,0);
int p=0; for(int i=1;i<=n;i++) if(dep[i] > dep[p]) p = i;
if(dep[b] <= da){puts("Alice"); continue;}
dep[p] = 0; dfs(p,0);
p=0; for(int i=1;i<=n;i++) if(dep[i] > dep[p]) p = i;
if(dep[p] > 2 * da && db > 2*da){puts("Bob"); continue;}
else{puts("Alice"); continue;}
}
}
C
定义每一个位置,它如果可以被消掉,肯定要满足
并且前面要消除掉
个
我们会发现每一个位置能不能消除,在于前面消除掉多少个,而前面消除掉多少个,与询问的
有关
我们不妨设
为如果第
个位置被消除掉,询问时的L出现的最大值。
对于一个
肯定是前面所有
中最大的
个消掉转移过来的,所以可以用一个线段树来维护
对于区间询问
,我们只需要问区间内有多少个
就好了
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define MP make_pair
#define fi first
#define se second
#define PB push_back
#define CL clear
#define pii pair<int,int>
#define int long long
using namespace std;
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int N = (int)(3e5) + 10;
const int mod = 1e9+7;
const int inf = 1e9 + 10;
const long double pi = acos(-1);
inline int rd() {
int p=0; int f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
int rt[N],tot,lc[N*20],rc[N*20],c[N*20];
void link(int &u,int L,int R,int k,int val)
{
if(!u) u=++tot;
if(L==R){c[u] += val; return ;}
int mid = (L+R)>>1;
if(k<=mid) link(lc[u],L,mid,k,val);
else link(rc[u],mid+1,R,k,val);
c[u] = c[lc[u]] + c[rc[u]];
}
int qry(int u,int L,int R,int k)
{
if(c[u] < k) return -inf;
if(L==R) return L;
int mid = (L+R)>>1;
if(c[rc[u]] >= k) return qry(rc[u],mid+1,R,k);
else return qry(lc[u],L,mid,k-c[rc[u]]);
}
void merge(int &u1,int u2) {
if(!u2) return ;
if(!u1){u1 = u2; return ;}
c[u1] += c[u2];
merge(lc[u1],lc[u2]);
merge(rc[u1],rc[u2]);
}
int qry2(int u1,int u2,int L,int R,int l,int r)
{
if(L==l && R==r) return c[u2] - c[u1];
int mid = (L+R)>>1;
if(r<=mid) return qry2(lc[u1],lc[u2],L,mid,l,r);
else if(l>mid) return qry2(rc[u1],rc[u2],mid+1,R,l,r);
else return qry2(lc[u1],lc[u2],L,mid,l,mid) + qry2(rc[u1],rc[u2],mid+1,R,mid+1,r);
}
int a[N]; int mx[N];
signed main() {
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
int n = rd(); int q = rd();
for(int i=1;i<=n;i++) a[i] = rd();
for(int i=1;i<=n;i++) a[i] = i- a[i];
rt[0] = tot = 0;
for(int i=1;i<=n;i++) if(a[i] >= 0) {
if(a[i] == 0) mx[i] = i;
else {
mx[i] = qry(rt[0],1,n,a[i]);
}
if(mx[i] != -inf) link(rt[0],1,n,mx[i],1);
// printf("%lld : %lld\n",i,mx[i]);
}else mx[i] = -inf;
for(int i=1;i<=tot;i++) lc[i] = rc[i] = c[i] = 0;
rt[0] = tot = 0;
for(int i=1;i<=n;i++) {
if(mx[i] != -inf) link(rt[i],1,n,mx[i],1);
merge(rt[i],rt[i-1]);
}
while(q--) {
int l = rd(); int r = rd(); l = l+1; r = n-r;
// printf("%lld %lld\n",l,r);
printf("%lld\n",qry2(rt[l-1],rt[r],1,n,l,r));
}
return 0;
}
D
考虑什么时候可以是
如果N是偶数的话,我们把
放在一起,这样的话,假设
,有:
在
下是不为
的,所以在
下也是不为
的
考虑N是奇数的情况:
这时我们把数分成两组,
,
,每一组在
下都是
,一组是加上奇数个
,一组是加上偶数个
我们同样是把
剩余
的数给选一遍,这样的话,选出来的两组数,在选中加上奇数个
的那一组数的个数来看,肯定一组是有奇数个,一组是有偶数个,所以我们根据
完后的情况再去调整就好了,这样就证明出来
的情况。
具体的做法就是把输入中同一组的,和 连边,然后黑白染色,这样就会出现很多个环,然后要不取黑色,要不取白色就好了。
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define MP make_pair
#define fi first
#define se second
#define PB push_back
#define CL clear
#define pii pair<int,int>
#define int long long
using namespace std;
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int N = (int)(1e6) + 10;
const int mod = 1e9+7;
const int inf = 1e9 + 10;
const long double pi = acos(-1);
inline int rd() {
int p=0; int f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
int n; vector<int> g[N],ans[2];
int px[N]; bool v[N];
void dfs(int x,int op) {
v[x] = 1; ans[op].PB(x);
for(auto u:g[x]) if(!v[u]) dfs(u,op^1);
}
signed main(){
cin >> n;
if(n % 2 == 0) {
cout << "First" << endl;
for(int i=1;i<=2*n;i++) cout << ((i <= n) ? i : (i-n)) << " ";
cout << endl;
int op; cin >> op;
assert(op == 0);
}
else {
cout << "Second" << endl;
for(int i=1;i<=2*n;i++) {
int x; cin >> x;
if(!px[x]) px[x] = i;
else g[i].PB(px[x]),g[px[x]].PB(i);
}
for(int i=1;i<=n;i++) g[i].PB(i+n),g[i+n].PB(i);
for(int i=1;i<=2*n;i++) if(!v[i]) dfs(i,0);
int s = 0;
for(int i=0;i<ans[0].size();i++) s+=ans[0][i];
if(s % (2*n) != 0) swap(ans[0],ans[1]);
for(int i=0;i<ans[0].size();i++) cout << ans[0][i] << " ";
cout << endl;
int op; cin >> op;
assert(op == 0);
}
}
E
把相邻两个
的边界变成点,把相邻的横着的边和竖着的边对应的点连线,跑一个最大独立集,跑出来的点集就是可以减少掉的边界。因为不能出现
形这种覆盖,所以要这样连边。
这样的二分图匹配跑一次网络流就好了。
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define MP make_pair
#define fi first
#define se second
#define PB push_back
#define CL clear
#define pii pair<int,int>
#define int long long
using namespace std;
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int N = (int)(2e2) + 10;
const int mod = 1e9+7;
const int inf = 1e9 + 10;
const long double pi = acos(-1);
inline int rd() {
int p=0; int f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
struct node{int x,y,nex,c,other;}edge[N*N*30]; int len,fir[N*N*4];
void ins(int x,int y,int c) {
len++; int k1 = len; edge[len].x=x; edge[len].y=y; edge[len].c=c; edge[len].nex = fir[x]; fir[x] = len;
len++; int k2 = len; edge[len].x=y; edge[len].y=x; edge[len].c=0; edge[len].nex = fir[y]; fir[y] = len;
edge[k1].other=k2; edge[k2].other = k1;
}
queue<int> q; int dep[N*N*4]; int s,d;
bool bfs() {
while(!q.empty()) q.pop();
memset(dep,0,sizeof(dep));
q.push(s); dep[s] = 1;
while(!q.empty()) {
int x = q.front();
for(int k=fir[x];k!=-1;k=edge[k].nex) {
int y = edge[k].y;
if(dep[y] == 0 && edge[k].c) {
dep[y] = dep[x] + 1;
q.push(y);
}
}q.pop();
}return dep[d] > 0;
}
int dfs(int x,int flow) {
if(x == d) return flow;
int delta = 0;
for(int k=fir[x];k!=-1;k=edge[k].nex) {
int y = edge[k].y;
if(dep[y] == dep[x] + 1 && edge[k].c && flow > delta) {
int minf = dfs(y,min(flow-delta,edge[k].c));
edge[k].c -= minf; edge[edge[k].other].c += minf; delta += minf;
}
}
if(delta == 0) dep[x] = 0;
return delta;
}
int MaxFlow() {
int ans = 0;
while(bfs()) {
ans += dfs(s,inf);
}return ans;
}
int n,m; char str[N][N]; int idL[N][N],idR[N][N],tot;
signed main(){
// freopen("a.in","r",stdin);
n = rd(); m = rd(); int ans = 0;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) {
scanf("\n%c",&str[i][j]);
if(str[i][j] == '#') ans ++;
}
len = 0; memset(fir,-1,sizeof(fir));
s = 1; d = 2; tot = 2;
for(int i=1;i<n;i++) for(int j=1;j<=m;j++) if(str[i][j] == '#' && str[i+1][j] == '#') idL[i][j] = ++tot,ins(s,idL[i][j],1);
for(int i=1;i<=n;i++) for(int j=1;j<m;j++) if(str[i][j] == '#' && str[i][j+1] == '#') idR[i][j] = ++tot,ins(idR[i][j],d,1);
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) {
if(idL[i][j] && idR[i][j]) ins(idL[i][j],idR[i][j],1);
if(idL[i-1][j] && idR[i][j]) ins(idL[i-1][j],idR[i][j],1);
if(idL[i][j] && idR[i][j-1]) ins(idL[i][j],idR[i][j-1],1);
if(idL[i][j] && idR[i+1][j-1]) ins(idL[i][j],idR[i+1][j-1],1);
}
// for(int i=1;i<=len;i++) printf("%lld %lld %lld\n",edge[i].x,edge[i].y,edge[i].c);
// printf("%lld %lld\n",((tot-2) >> 1) , MaxFlow());
return printf("%lld\n",ans - ((tot-2) - MaxFlow())),0;
}