[IOI2018]-day1 简要题解
- 【题目地址:T1-组合动作】
因为只有4种字母,且只能询问n+2n+2n+2次,那么我们需要平均一次就要确定一位。
而询问的串长,最长为4×n4\times n4×n,所以每次对于一个要确定的字母我们可以直接输出四种情况。但是这样需要2次确定一位,所以我们需要进一步优化。
首先,我们可以花两步确定第一位:
询问"AB",如果返回的值大于0,则就是"AB"中的一个,然后就输出一个"A",如果返回值为1,那么开头就是"A",否则为"B"。如果不是"AB",那么就是"XY",所以输出"X",和"AB"同样的判断方法,那么就可以知道第一位。
对于后面的每一位,我们要尽量做到一次询问确定一位。由于开头的那一位不会在后面再次出现,那么我们只剩下三种选择。
举个例子说明:
假如开头是"A",那么下一位可能为"B,X,Y",而如果每次只增加一位的话,就还要花费一个操作去确定,所以我们增加两位:“BB”,“BX”,“BY”,这样如果返回值没有增加,下一位就不是"B",但是如果增加了两个,那么下一位就是"B",如果不是"B"的话,还要判断"X,Y",由于"A"不能再出现,所以我们再加一个"XA",这样如果返回值只增加了一个,那么下一位就是"X",否则没增加就是"Y"。
所以直接模拟,而到了最后一位,直接按照开始的方法,在剩下三种情况中花费两个操作判断一下即可。
代码(交互):
#include "combo.h"
using namespace std;string Nex(char a,int id){if(a=='A'){if(id==1) return "BB";if(id==2) return "BX";if(id==3) return "BY";if(id==4) return "XA";}else if(a=='B'){if(id==1) return "AA";if(id==2) return "AX";if(id==3) return "AY";if(id==4) return "XB";}else if(a=='X'){if(id==1) return "AA";if(id==2) return "AB";if(id==3) return "AY";if(id==4) return "BX";}else if(a=='Y'){if(id==1) return "AA";if(id==2) return "AB";if(id==3) return "AX";if(id==4) return "BY"; }
}
string Ok(char a,int con,int bef){if(a=='A'){if(con==bef){return "Y";}else if(con==bef+1){return "X";}else if(con==bef+2){return "B";}}else if(a=='B'){if(con==bef){return "Y";}else if(con==bef+1){return "X";}else if(con==bef+2){return "A";} }else if(a=='X'){if(con==bef){return "Y";}else if(con==bef+1){return "B";}else if(con==bef+2){return "A";} }else if(a=='Y'){if(con==bef){return "X";}else if(con==bef+1){return "B";}else if(con==bef+2){return "A";} }
}
string End(char a,int id){if(a=='A'){if(id==1){return "B";}else if(id==2){return "X";}else if(id==3){return "Y";}}else if(a=='B'){if(id==1){return "A";}else if(id==2){return "X";}else if(id==3){return "Y";} }else if(a=='X'){if(id==1){return "A";}else if(id==2){return "B";}else if(id==3){return "Y";} }else if(a=='Y'){if(id==1){return "A";}else if(id==2){return "B";}else if(id==3){return "X";} }
}
string guess_sequence(int N){string st="";string pre="AB";int con=press(pre);if(!con){con=press("X");if(con) st="X";else st="Y";}else{con=press("A");if(con) st="A";else st="B";}pre=st;if(N==1) return pre;for(int i=2;i<=N-1;i++){string ask="";for(int j=1;j<=4;j++)ask+=pre+Nex(st[0],j);con=press(ask);pre+=Ok(st[0],con,i-1);}string last=pre+End(st[0],1)+pre+End(st[0],2);con=press(last);if(con==N-1){last=pre+End(st[0],3);}else{last=pre+End(st[0],1);con=press(last);if(con==N-1){last=pre+End(st[0],2);}}return last;
}
- 【题目地址:T2-排座位】
开始我想的是,对于一个前缀0∼L0\sim L0∼L,我们维护里面最左下角的点和最右上角的点,然后每次询问我们就判断每个前缀数的个数是不是等于所在矩形区间的大小,为了支持快速查询修改,外面再套一个树,或者用主席树之类的,但是就是十分复杂,且复杂度为O(nlog2n)O(nlog^2n)O(nlog2n)的,是无法通过所有数据的。
所以我们转换思路,对于一个前缀0∼L0\sim L0∼L如果它形成了一个矩形,那么与其相交的所有2×22\times 22×2的子矩形要么是只有两个相交,要么是全部在里面,要么是只有一个相交,而一个的只有矩形的四个顶点,而三个相交的又不存在,但是2,4个的个数不确定,所以我们就只维护对于一个前缀0∼L0\sim L0∼L的所在格子形成的图形与其相交的所有2×22\times 22×2的子矩形中1,31,31,3的个数,如果合法的话必须只有4,04,04,0个。
这个可以先预处理出来,然后用权值线段树维护即可,每次修改就交换然后线段树上改这两个点周围包含它的2×22\times 22×2的子矩形即可,复杂度O(nlogn)O(nlogn)O(nlogn)。
#include "seats.h"#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=1e6+10;vector <int> mp[M];
int rr[M],cc[M];
int B1[M],B3[M];
int n,m;
struct node{int b1,b3;node(){}node(int a,int b):b1(a),b3(b){}bool operator <(const node &a)const{return b1<a.b1||(b1==a.b1&&b3<a.b3);}node operator +(const node &a)const{return node(b1+a.b1,b3+a.b3); }bool operator ==(const node &a)const{return b1==a.b1&&b3==a.b3; }node operator +=(const node &a){return *this=*this+a;}bool isok(){return b1==4&&!b3;}
};int tot,root;
node S[M<<2],lazy[M<<2];
int ls[M<<2],rs[M<<2],sum[M<<2];void pushup(int o){S[o]=min(S[ls[o]],S[rs[o]]);sum[o]=0;if(S[o]==S[ls[o]])sum[o]+=sum[ls[o]];if(S[o]==S[rs[o]])sum[o]+=sum[rs[o]];
}
void pushdown(int o){node &now=lazy[o];if(now==node(0,0)) return;S[ls[o]]+=now;S[rs[o]]+=now;lazy[ls[o]]+=now;lazy[rs[o]]+=now;now=node(0,0);
}
void build(int &o,int l,int r){o=++tot;lazy[o]=node(0,0);if(l==r){S[o]=node(B1[l],B3[l]);sum[o]=1;return;}int mid=l+r>>1;build(ls[o],l,mid);build(rs[o],mid+1,r);pushup(o);
}
void update(int o,int l,int r,int L,int R,node v){if(L>R) return;if(L<=l&&r<=R){S[o]+=v;lazy[o]+=v;return;}pushdown(o);int mid=l+r>>1;if(L<=mid) update(ls[o],l,mid,L,R,v);if(R>mid) update(rs[o],mid+1,r,L,R,v);pushup(o);
}
int query(){if(S[root].isok()) return sum[root];else return 0;
}
int stk[4];
const int dx[]={0,1,0,1},dy[]={0,0,1,1};
void init(int x,int y){for(int i=0;i<=3;i++){stk[i]=mp[x+dx[i]][y+dy[i]];} sort(stk,stk+4);
}
void give_initial_chart(int H, int W, std::vector<int> R, std::vector<int> C) {n=H,m=W;for(int i=0;i<=n+1;i++){mp[i].resize(m+2);for(int j=0;j<=m+1;j++){mp[i][j]=n*m+1;}}for(int i=1,sz=n*m;i<=sz;i++){rr[i]=R[i-1]+1;cc[i]=C[i-1]+1;mp[rr[i]][cc[i]]=i;}for(int i=0;i<=n;i++)for(int j=0;j<=m;j++){init(i,j);++B1[stk[0]];--B1[stk[1]];++B3[stk[2]];--B3[stk[3]];}for(int i=1,sz=n*m;i<=sz;i++){B1[i]+=B1[i-1];B3[i]+=B3[i-1];}build(root,1,n*m);
}
void New(int x,int y,int v){init(x,y);update(root,1,n*m,stk[0],stk[1]-1,node(v,0));update(root,1,n*m,stk[2],stk[3]-1,node(0,v));
}
const int tx[]={0,-1,0,-1},ty[]={0,0,-1,-1};
void Up(int x,int y,int v){for(int i=0;i<=3;i++)New(x+tx[i],y+ty[i],-1);mp[x][y]=v;for(int i=0;i<=3;i++)New(x+tx[i],y+ty[i],1);
}
int swap_seats(int a, int b) {++a;++b;int v1=mp[rr[a]][cc[a]],v2=mp[rr[b]][cc[b]];swap(rr[a],rr[b]);swap(cc[a],cc[b]);Up(rr[a],cc[a],v1);Up(rr[b],cc[b],v2);return query();
}
- 【题目地址:T3-狼人】
由于每次每种形态不能去和能去的都是一个编号的前缀或者后缀,所以我们考虑将图转换成两个重构树,一个是编号小的向大的,另一个是编号大的向小的。
然后一个前缀就对应了小的向大的树上的一个子树,后缀就对应了大的向小的上面的一个子树,每次用类似二维数点的方式判断这两个子树集合是否有交,有交就证明可以在这里变成狼人到达终点,否则就不行。
将询问离线,在两个树上的dfs序上,就可以用树状数组来求答案啦。
这里的重构树的方法类似于kruskal重构树,所以用个并查集来建就好了。
#include "werewolf.h"#include<cstdio>
#include<cstring>
#include<algorithm>
#define lowbit(a) ((a)&(-(a)))
using namespace std;
const int M=1e6+1;
const int Log=20;
struct DSU{int f[M];void init(int n){for(int i=0;i<=n;i++)f[i]=i;}int find(int a){return f[a]==a?a:f[a]=find(f[a]);}int & operator [](int a){return f[a];}int operator ()(int a){return find(a);}
};
int n;
struct Rebuild_Tree{vector <int> g[M],t[M];int in[M],root;void add(int a,int b){g[a].push_back(b);}void link(int a,int b){t[a].push_back(b);++in[b];}DSU F;int dfn[M],out[M],tim;int f[Log][M];void dfs(int a){dfn[a]=++tim;for(int i=1;i<Log;i++)f[i][a]=f[i-1][f[i-1][a]];for(auto v: t[a]){f[0][v]=a;dfs(v);}out[a]=tim;}void build(bool flag){F.init(n);if(flag){for(int i=1,u;i<=n;i++){for(auto v: g[i]){u=F(v);if(i!=u){F[u]=i;link(i,u);}}}}else{for(int i=n,u;i>=1;i--){for(auto v: g[i]){u=F(v);if(i!=u){F[u]=i;link(i,u);}} }}for(int i=1;i<=n;i++)if(!in[i]){root=i;break;}dfs(root);}void Find(int a,int to,int tp,int &x,int &y){for(int i=Log-1;i>=0;i--){if(f[i][a]&&(tp?f[i][a]>=to:f[i][a]<=to)){a=f[i][a];}}x=dfn[a]-1;y=out[a];}
}T1,T2;
int bit[M];
void add(int a,int b){for(;a<=n;a+=lowbit(a))bit[a]+=b;
}
int query(int a){int res=0;for(;a;a-=lowbit(a))res+=bit[a];return res;
}
struct Ask{int s,t;Ask(){}Ask(int a,int b):s(a),t(b){}
};
vector <Ask> Q[M];
vector <int> ans;
int ref[M];
int a,b;
vector<int> check_validity(int N,vector<int> X,vector<int> Y,vector<int> S,vector<int> E,vector<int> L,vector<int> R) {n=N;for(int i=0,sz=X.size();i<sz;i++){a=X[i]+1;b=Y[i]+1;if(a<b)swap(a,b);T1.add(a,b);T2.add(b,a);}T1.build(1);T2.build(0);for(int i=0,sz=S.size(),lx,rx,ly,ry;i<sz;i++){T2.Find(S[i]+1,L[i]+1,1,lx,rx);T1.Find(E[i]+1,R[i]+1,0,ly,ry);Q[lx].push_back(Ask(ly,i));Q[lx].push_back(Ask(-ry,i));Q[rx].push_back(Ask(-ly,i));Q[rx].push_back(Ask(ry,i));}for(int i=1;i<=n;i++)ref[T2.dfn[i]]=T1.dfn[i];ans.resize(S.size());for(int i=1;i<=n;i++){add(ref[i],1);for(int j=0,sz=Q[i].size();j<sz;j++){Ask now=Q[i][j];int fl=now.s<0?now.s=-now.s,-1:1;ans[now.t]+=query(now.s)*fl;}} for(int i=0,sz=ans.size();i<sz;i++)if(ans[i]>0)ans[i]=1;else ans[i]=0;return ans;
}
[IOI2018]-day1 简要题解相关推荐
- 【FJWC】day1简要题解
题面 fc B I T BIT BIT维护前缀 m a x max max. 复杂度 O ( n log n ) O(n\log n) O(nlogn) copy n = 1 n=1 n=1直接建 ...
- Noip 2014酱油记+简要题解
好吧,day2T1把d默认为1也是醉了,现在只能期待数据弱然后怒卡一等线吧QAQ Day0 第一次下午出发啊真是不错,才2小时左右就到了233,在车上把sao和fate补掉就到了= = 然后到宾馆之后 ...
- 杂题记录及简要题解(一)
一些前几天做过的还不错的但是不是太想专门花一整篇博客的篇幅去写的题就简要地记录在这里. 说是简要题解,其实写得还是挺详细的.之后的杂题记录可能就会写得简略一点. CF1060E Sergey and ...
- c语言1106回文数,Codeforces 1106 简要题解
A题 传送门 读错题还能过样例我给自己点个赞. 题意简述:给一个010101网格SSS,问满足Si,j=Si+1,j+1=Si+1,j−1=Si−1,j−1=Si−1,j+1S_{i,j}=S_{i+ ...
- 湖南省第十届蓝狐网络杯大学生计算机程序设计竞赛,2019年湖南省大学生计算机程序设计竞赛 (HNCPC2019) 简要题解...
2019年湖南省大学生计算机程序设计竞赛 (HNCPC2019) 简要题解 update10.01 突然发现叉姐把这场的题传到牛客上了,现在大家可以有地方提交了呢. 不知道该干什么所以就来水一篇题解 ...
- BJOI2018简要题解
BJOI2018简要题解 D1T1 二进制 题意 pupil 发现对于一个十进制数,无论怎么将其的数字重新排列,均不影响其是不是 \(3\) 的倍数.他想研究对于二进制,是否也有类似的性质. 于是他生 ...
- 【BJOI2019 Day1】简要题解
T1: 传送门 很显然是要在AcAcAc自动机上dpdpdp 一个显然的dpdpdp是f[i][j][k]f[i][j][k]f[i][j][k]表示前iii个字符,当前在自动机的点jjj,已经有kk ...
- 【NOI2019十二省联合省选】部分题简要题解
Day 1 T1 异或粽子 题意:给出一个长为n的序列,选择K个不完全重合的区间使得每个区间的异或值的总和最大. 题解:先做一个前缀异或和,对于每一个右端点我们记录三元组(l,r,x)表示在左端点在\ ...
- Codeforces 1110 简要题解
文章目录 A题 B题 C题 D题 E题 F题 G题 传送门 众所周知ldxoildxoildxoi这种菜鸡选手是不会写HHH题的,因此该篇博客只有AAA题至GGG题的题解,实在抱歉. A题 传送门 题 ...
- 【HNOI2019】部分题简要题解
题意懒得写了 LOJ Day 1 T1 鱼 个人做法比较猎奇,如果有哪位大佬会证明能分享一下的话感激不尽. 题解:枚举鱼尾和鱼身的交点D,将所有其他点按照到D的距离排序,距离相同的分一组. 感性的理解 ...
最新文章
- mvc3 之三 符号列表
- Python进阶之路:namedtuple
- Redis(十一):Redis特殊类型之Bitmap位图
- 透过一个编译报错,总结两个Go程序编译的重要知识
- 核心对象+持久对象全析(3)
- piv图像处理文献综述_图像处理文献综述
- Linux触摸屏驱动分析(6410) -- s3c-ts
- 更改session bean的JNDI名称
- c语言程序设计爱心图片,c语言爱心图片表白程序源代码
- cpu开启超线程linux,Linux开发人员声称除非禁用超线程否则可以利用英特尔CPU
- 大连理工大学软件学院2022年秋季学期《矩阵与数值分析》上机作业
- 掷骰子python代码_Python之使用Pygal模拟掷骰子
- 微信企业号开发:企业支付成功后关闭交易页面问题
- 每日文献:2018-01-29
- 政府OA办公系统实施时需要关注的五个环节
- ConcurrentHashMap 的理解
- M.2的SATA和M.2的NVME协议的区别
- 【完美解决】android开发 自定义字体安装包过大的问题
- 浅析PoE技术与视频监控传输市场
- 网站VI设计之VI设计的误区
热门文章
- WinEdit + CTex 打开论文模板出现乱码
- python100天从新手到大师下载_GitHub - longers/Python-100-Days: Python - 100天从新手到大师...
- 「补课」进行时:设计模式(2)——通过一个超级汽车工厂来了解工厂模式
- 方法重载时,需要遵循以下三条原则
- InfoPath 2007表单应用
- 用matlab加数字水印,MATLAB数字水印系统设计
- java弹弹球实验报告_Java程序设计实验报告2(弹球游戏)1
- 计算机发展的雏形,( )是现代计算机的雏形。
- python 因子分析 权重计算_Python与量化多因子——因子权重优化
- 解决微信开发工具卡顿的问题