D. Dasha and Chess
交互题,黑白棋互奕,白棋与某个黑棋同行或者同列即可获胜。
利用棋盘大小和黑棋数量的性质就可以知道策略了。
移动白子到棋盘中心,然后往某个角落走,那么在500步内就能扫过棋盘的棋盘的3/4,而四等分棋盘后黑棋数量多的那三分是超过500个棋子的,所以往那个角落走一定能成功。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
const int maxn=1000+15;
const int maxe=1e5+15;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
int n,m;
pii pos[maxn];
int ma[maxn][maxn];
int tot=0;
void print(int a,int b){
tot++;
cout<<a<<" "<<b<<endl;
cout.flush();
int aa,bb,cc;
cin>>aa>>bb>>cc;
if(aa==-1||aa==0)exit(0);
ma[pos[aa].fi][pos[aa].se]=0;
pos[aa]=mp(bb,cc);
ma[pos[aa].fi][pos[aa].se]=aa;
if(tot==2000)exit(0);
}
int cntx,cnty;
int cc[4];
int main(){
cin>>cntx>>cnty;
for(int i=1,a,b;i<=666;i++){
scanf("%d%d",&pos[i].fi,&pos[i].se);
ma[pos[i].fi][pos[i].se]=i;
}
while(cntx<500){
print(cntx+1,cnty);
cntx++;
}
while(cntx>500){
print(cntx-1,cnty);
cntx--;
}
while(cnty<500){
print(cntx,cnty+1);
cnty++;
}
while(cnty>500){
print(cntx,cnty-1);
cnty--;
}
for(int i=1;i<=666;i++){
if(pos[i].fi<500&&pos[i].se<500)cc[0]++;
if(pos[i].fi<500&&pos[i].se>500)cc[1]++;
if(pos[i].fi>500&&pos[i].se<500)cc[2]++;
if(pos[i].fi>500&&pos[i].se>500)cc[3]++;
}
int mi=1000;
for(int i=0;i<4;i++)mi=min(mi,cc[i]);
int dx,dy;
if(mi==cc[0]){dx=1;dy=1;}
else if(mi==cc[1]){dx=1;dy=-1;}
else if(mi==cc[2]){dx=-1;dy=1;}
else {dx=-1;dy=-1;}
while(1){
if(ma[cntx+dx][cnty+dy]==0){
print(cntx+dx,cnty+dy);
cntx+=dx,cnty+=dy;
continue;
}
print(cntx+dx,cnty);
cntx+=dx;
print(cntx,cnty+dy);
cnty+=dy;
}
return 0;
}
E. Andrew and Taxi
消除图中的环,最小化最大所需翻转边的权值。
二分答案,小于mid的边无视掉,判剩余图是否能拓扑排序即可。
构造方案只要按照拓扑排序确定小于mid的边的顺序即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
const int maxn=1e5+15;
const int maxe=1e5+15;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
int n,m;
struct edge{
int to,len,nxt,id;
}e[maxe];
int head[maxn];
int tot;
void adde(int u,int v,int len,int id){
e[tot].to=v;
e[tot].len=len;
e[tot].id=id;
e[tot].nxt=head[u];
head[u]=tot++;
}
int id[maxn];
int deg[maxn];
bool check(int mid){
memset(id,-1,sizeof(id));
memset(deg,0,sizeof(deg));
int idtot=1;
for(int u=1;u<=n;u++){
for(int i=head[u];i!=-1;i=e[i].nxt){
if(e[i].len<=mid)continue;
deg[e[i].to]++;
}
}
queue<int> que;
for(int i=1;i<=n;i++){
if(deg[i]==0)que.push(i);
}
while(!que.empty()){
int u=que.front();que.pop();
id[u]=idtot++;
for(int i=head[u];i!=-1;i=e[i].nxt){
if(e[i].len<=mid)continue;
int v=e[i].to;
deg[v]--;
if(deg[v]==0)que.push(v);
}
}
if(idtot==n+1)return 1;
return 0;
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=0,a,b,c;i<m;i++){
scanf("%d%d%d",&a,&b,&c);
adde(a,b,c,i+1);
}
int lef=0,rig=1e9,ret;
while(lef<=rig){
int mid=(lef+rig)>>1;
if(check(mid)){ret=mid;rig=mid-1;}
else lef=mid+1;
}
check(ret);
vector<int> vec;
for(int u=1;u<=n;u++){
for(int i=head[u];i!=-1;i=e[i].nxt){
if(e[i].len>ret)continue;
if(id[u]>id[e[i].to])vec.pb(e[i].id);
}
}
sort(vec.begin(),vec.end());
printf("%d %d\n",ret,vec.size());
for(auto v:vec){
printf("%d ",v);
}
return 0;
}
F. Ivan and Burgers
区间查询异或的最大值
离线,按照询问构造线性基,尽量让使用靠近右边的数构成线性基,然后询问就可以使用位置大于询问左边界的线性基贪心得出答案。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
const int maxn=5e5+105;
int n,q;
struct query{
int l,r,id;
}que[maxn];
bool cmp(query a,query b){
return a.r<b.r;
}
int c[maxn];
int ans[maxn];
int p[21],pos[21];
void add(int num,int ppp){
for(int i=20;i>=0;i--){
if(num>>i&1){
if(p[i]==0){
p[i]=num;pos[i]=ppp;
break;
}
if(pos[i]<ppp){
swap(num,p[i]);
swap(pos[i],ppp);
}
num^=p[i];
}
}
}
int query(int x){
int ret=0;
for(int i=20;i>=0;i--){
if(pos[i]>=x&&(ret^p[i])>ret)ret^=p[i];
}
return ret;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&c[i]);
scanf("%d",&q);
for(int i=0;i<q;i++){
scanf("%d%d",&que[i].l,&que[i].r);
que[i].id=i;
}
sort(que,que+q,cmp);
int cnt=1;
for(int i=0;i<q;i++){
while(cnt<=que[i].r&&cnt<=n){
add(c[cnt],cnt);
cnt++;
}
ans[que[i].id]=query(que[i].l);
}
for(int i=0;i<q;i++)printf("%d\n",ans[i]);
return 0;
}