XIII Open Cup named after E.V. Pankratiev. GP of Saratov
A. Box Game
注意到局面总数不超过$50000$,而且每次操作都会改变石子的奇偶性,因此按奇偶可以将状态建成二分图,然后求出最大匹配。
如果状态数是偶数,那么先手必胜,策略就是每次走匹配边,那么对手不能通过匹配边走回来,因此所有匹配边你都能走掉。
如果状态数是奇数,那么如果此时有奇数个石子,也是先手必胜,因为最后对手会遭遇怎么走都会回到以前走过的局面的困境。
选择完先后手之后,每次按匹配边走下去即可。
B. Circle of Stones
首先将环倍长,破环成链,那么剩下的子串要满足相邻字符不同且首尾字符不同。
通过双指针求出每一段极长的子串,满足相邻字符不同,设这一段长度为$len$,从$2$到$len$枚举剩下的串的长度$L$,若该子串长度为$len-L+1$的前后缀不能完全匹配,则说明存在距离为$L-1$的位置不同,也就能充当首尾,Hash判断即可。
时间复杂度$O(n)$。
#include<cstdio>
#include<cstring>
typedef long long ll;
const int N=2000010,D=233,P=1000000009;
int C,n,m,i,j,k,len;char a[N],ans[N];ll pow[N],f[N];
inline ll hash(int l,int r){return((f[r]-f[l-1]*pow[r-l+1])%P+P)%P;}
int main(){
for(pow[0]=i=1;i<N;i++)pow[i]=pow[i-1]*D%P;
while(~scanf("%s",a+1)){
n=strlen(a+1);m=n+n;
for(i=1;i<=n;i++)a[i+n]=a[i];
for(i=1;i<=m;i++)f[i]=(f[i-1]*D+a[i])%P;
for(i=0;i<n;i++)ans[i]='0';
for(i=1;i<=m;i=j+1){
for(j=i;j<m&&a[j]!=a[j+1];j++);
len=j-i+1;
for(k=2;k<=len&&k<=n;k++)if(hash(i,i+len-k)!=hash(j-len+k,j))ans[n-k]='1';
}
for(printf("Case %d: ",++C),i=0;i<n-1;i++)putchar(ans[i]);puts("1");
}
return 0;
}
C. Expression with Sets
留坑。
D. Heating System
留坑。
E. Islands
留坑。
F. Longest Two Graphs Common String
设$f[i][j][0]$表示选出的路径里,第一张图中最后一个点是$i$,第二张图中最后一个点是$j$的最大长度。
设$f[i][j][1]$表示选出的路径里,第一张图中最后一个点再往后乱走一步到了$i$,第二张图中最后一个点是$j$的最大长度。
则对于$f[i][j][0]$,只需要枚举指向$j$的边,用$f[i][j'][1]$转移;对于$f[i][j][1]$,只需要枚举指向$i$的边,用$f[i'][j][0]$转移。
时间复杂度$O(n(n+m))$。
#include<cstdio>
const int N=505,M=4010;
int T,n1,n2,m,i,j,k,flag,ans,X,Y,q[N*N][2];
int f[N][N][2],pre[N][N][2];
bool v[N][N][2],vis[N][N][2];
struct G{
int n,g[N],v[M],nxt[M],ed;
int i,x,y;
char a[N];
void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void init(int _n,int m){
n=_n;
scanf("%s",a+1);
for(ed=0,i=1;i<=n;i++)g[i]=0;
while(m--)scanf("%d%d",&x,&y),add(y,x);
}
}G1,G2;
void dp(int x,int y,int z){
if(vis[x][y][z])flag=1;
if(flag)return;
if(v[x][y][z])return;
vis[x][y][z]=v[x][y][z]=1;
int&t=f[x][y][z],&p=pre[x][y][z];
t=-1,p=0;
if(z==0){
if(G1.a[x]==G2.a[y]){
t=0;
for(int i=G2.g[y];i;i=G2.nxt[i]){
int k=G2.v[i];
dp(x,k,z^1);
if(f[x][k][z^1]>t)t=f[x][k][z^1],p=k;
}
if(~t)t++;
}
}else{
for(int i=G1.g[x];i;i=G1.nxt[i]){
int k=G1.v[i];
dp(k,y,z^1);
if(f[k][y][z^1]>t)t=f[k][y][z^1],p=k;
}
}
vis[x][y][z]=0;
}
int main(){
while(~scanf("%d%d",&n1,&m)){
G1.init(n1,m);
scanf("%d%d",&n2,&m);
G2.init(n2,m);
for(i=1;i<=n1;i++)for(j=1;j<=n2;j++)for(k=0;k<2;k++)v[i][j][k]=vis[i][j][k]=0;
ans=flag=0;
for(i=1;i<=n1;i++)for(j=1;j<=n2;j++){
dp(i,j,0);
if(f[i][j][0]>ans)ans=f[i][j][0],X=i,Y=j;
}
printf("Case %d: ",++T);
if(flag)puts("-1");else{
printf("%d\n",ans);
for(i=ans;i;i--){
q[i][0]=X,q[i][1]=Y;
Y=pre[X][Y][0];
X=pre[X][Y][1];
}
for(i=1;i<=ans;i++)printf("%d%c",q[i][0],i<ans?' ':'\n');
for(i=1;i<=ans;i++)printf("%d%c",q[i][1],i<ans?' ':'\n');
}
}
return 0;
}
G. Lyndon Words
找规律构造,可以$O(n)$生成字典序下一个,暴力生成出字典序前$r$小的所有串即可。
时间复杂度$O(nr)$。
H. Temperature
状压DP。
时间复杂度$O(n2^n)$。
I. Editor 2
留坑。
J. Tourist Problem
留坑。
K. Ant versus Woodpecker
显然答案就是虚树上度数$>1$的点的深度的最大值,用ETT维护dfs序并支持查询lca即可。
时间复杂度$O((m+\sum k)\log n)$。
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
const int N=400010;
int C,n,m,i,x,g[N],Nxt[N];
int vis[N],a[N],dfn[N],deg[N],t,q[N];
int id[N];
int d[N],st[N],en[N],pre[N],nxt[N],val[N],md[N],size[N],son[N][2],f[N],tot,root;
set<int>T;
inline void up(int x){
md[x]=val[x];
size[x]=1;
if(son[x][0]){
if(d[md[son[x][0]]]<d[md[x]])md[x]=md[son[x][0]];
size[x]+=size[son[x][0]];
}
if(son[x][1]){
if(d[md[son[x][1]]]<d[md[x]])md[x]=md[son[x][1]];
size[x]+=size[son[x][1]];
}
}
inline void rotate(int x){
int y=f[x],w=son[y][1]==x;
son[y][w]=son[x][w^1];
if(son[x][w^1])f[son[x][w^1]]=y;
if(f[y]){
int z=f[y];
if(son[z][0]==y)son[z][0]=x;
if(son[z][1]==y)son[z][1]=x;
}
f[x]=f[y];son[x][w^1]=y;f[y]=x;up(y);
}
inline void splay(int x,int w){
while(f[x]!=w){
int y=f[x];
if(f[y]!=w){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
rotate(x);
}
if(!w)root=x;
up(x);
}
inline int getrank(int x){
splay(x,0);
return size[son[x][0]];
}
inline void addnode(int x,int y){//x father is y
d[x]=d[y]+1;
int z=nxt[st[y]];
splay(st[y],0);
splay(z,root);
son[z][0]=++tot;
val[tot]=x;
f[tot]=z;
st[x]=tot;
id[tot]=x;
son[st[x]][1]=++tot;
f[tot]=st[x];
val[tot]=y;
en[x]=tot;
up(tot);
up(st[x]);
up(z);
up(root);
nxt[root]=st[x];
nxt[st[x]]=en[x];
nxt[en[x]]=z;
pre[z]=en[x];
pre[en[x]]=st[x];
pre[st[x]]=root;
}
void dfsdel(int x){
if(!x)return;
if(id[x])T.insert(id[x]);
dfsdel(son[x][0]);
dfsdel(son[x][1]);
}
inline void delsubtree(int x){
splay(pre[st[x]],0);
splay(nxt[en[x]],root);
int z=son[root][1];
nxt[root]=z;
pre[z]=root;
dfsdel(son[z][0]);
son[z][0]=0;
up(z);
up(root);
}
void show(int x){
if(!x)return;
show(son[x][0]);
printf("%d ",val[x]);
show(son[x][1]);
}
inline int lca(int x,int y){
if(x==y)return x;
if(x==1||y==1)return 1;
if(getrank(st[x])>getrank(st[y]))swap(x,y);
splay(pre[st[x]],0);
splay(nxt[st[y]],root);
return md[son[son[root][1]][0]];
}
int build(int l,int r,int fa){
int mid=(l+r)>>1;
f[mid]=fa;
if(l<mid)son[mid][0]=build(l,mid-1,mid);
if(r>mid)son[mid][1]=build(mid+1,r,mid);
up(mid);
return mid;
}
inline bool cmp(int x,int y){return dfn[x]<dfn[y];}
void dfs(int x){
for(int i=g[x];i;i=Nxt[i]){
d[i]=d[x]+1;
st[i]=++tot;
val[tot]=i;
dfs(i);
en[i]=++tot;
val[tot]=x;
}
}
inline int getid(){
int x=*T.begin();
T.erase(x);
return x;
}
int main(){
while(~scanf("%d",&n)){
st[1]=1;
val[1]=1;
tot=1;
for(i=2;i<=n;i++){
scanf("%d",&x);
Nxt[i]=g[x];
g[x]=i;
}
dfs(1);
en[1]=++tot;
val[tot]=1;
for(i=1;i<tot;i++){
pre[i+1]=i;
nxt[i]=i+1;
}
for(i=1;i<=n;i++)id[st[i]]=i;
root=build(1,tot,0);
int mm;
scanf("%d",&mm);
int lim=n+mm;
T.clear();
for(i=n+1;i<=n+mm;i++)T.insert(i);
int last=0;
printf("Case %d:",++C);
while(mm--){
char op[5];
scanf("%s",op);
if(op[0]=='+'){
int x;
scanf("%d",&x);
int y=getid();
x+=last;
addnode(y,x);
}
if(op[0]=='-'){
int x;
scanf("%d",&x);
delsubtree(x);
}
if(op[0]=='?'){
//show(root);puts("");
scanf("%d",&m);
int cnt=1;
a[1]=1;
vis[1]=1;
dfn[1]=getrank(st[1]);
while(m--){
scanf("%d",&x);
if(!vis[x]){
a[++cnt]=x,vis[x]=1;
dfn[x]=getrank(st[x]);
}
}
//for(i=1;i<=cnt;i++)printf("%d ",a[i]);puts("");
sort(a+1,a+cnt+1,cmp);
int now=cnt;
for(i=1;i<cnt;i++)if(!vis[x=lca(a[i],a[i+1])]){
vis[a[++now]=x]=1;
dfn[x]=getrank(st[x]);
}
sort(a+1,a+now+1,cmp);
//for(i=1;i<=now;i++)printf("%d ",a[i]);puts("");
last=-1;
for(q[t=1]=1,i=2;i<=now;q[++t]=a[i++]){
while(lca(a[i],q[t])!=q[t])t--;
deg[q[t]]++;
if(deg[q[t]]>1)last=max(last,d[q[t]]);
//printf("edge %d %d\n",q[t],a[i]);
}
printf(" %d",last);
for(i=1;i<=now;i++)vis[a[i]]=deg[a[i]]=0;
}
}
puts("");
for(i=1;i<=lim;i++)st[i]=en[i]=d[i]=g[i]=0;
for(i=0;i<=tot+1;i++)id[i]=pre[i]=nxt[i]=val[i]=md[i]=size[i]=son[i][0]=son[i][1]=f[i]=0;
tot=root=0;
}
return 0;
}
XIII Open Cup named after E.V. Pankratiev. GP of Saratov的更多相关文章
- XIII Open Cup named after E.V. Pankratiev. GP of Ukraine
A. Automaton 后缀自动机可以得到$O(2n+1)$个状态,但是后缀自动机会拒绝接收所有不是$S$的子串的串,所以在建立后缀自动机的时候不复制节点即可得到$n+1$个状态的DFA. #inc ...
- XIII Open Cup named after E.V. Pankratiev. GP of Asia and South Caucasus
A. RPG 首先计算出每个技能对于每个属性值的可行区间,若区间为空则不合法. 枚举两个技能,以及每个属性值,根据区间的关系可以得到哪个必须要在另一个之前学,连边看看是否有环即可. 时间复杂度$O(n ...
- XIII Open Cup named after E.V. Pankratiev. GP of Azov Sea
A. Freestyle 如果逆序对为$0$,那么先手必败. 因为每次只能翻转长度为$4k+2$和$4k+3$的区间,所以每次操作之后逆序对的奇偶性一定会发生改变. 因此如果逆序对个数为偶数,则先手必 ...
- XIII Open Cup named after E.V. Pankratiev. GP of America
A. Explosions 注意到将炸弹按坐标排序后,每个炸弹直接引爆和间接引爆的都是连续的一段区间,因此只需要求出每个炸弹能间接炸到的最左和最右的炸弹即可. 建立图论模型,炸弹$i$向炸弹$j$连单 ...
- XIII Open Cup named after E.V. Pankratiev. GP of SPb
A. Graph Coloring 答案为$1$很好判,为$2$只需要二分图染色,对于$3$,首先爆搜哪些边要染成第$3$种颜色,然后二分图染色判定即可. B. Decimal Fraction 枚举 ...
- XV Open Cup named after E.V. Pankratiev. GP of Tatarstan
A. Survival Route 留坑. B. Dispersed parentheses $f[i][j][k]$表示长度为$i$,未匹配的左括号数为$j$,最多的未匹配左括号数为$k$的方案数. ...
- XVII Open Cup named after E.V. Pankratiev. GP of SPb
A. Array Factory 将下标按前缀和排序,然后双指针,维护最大的右边界即可. #include<cstdio> #include<algorithm> using ...
- XVI Open Cup named after E.V. Pankratiev. GP of Ukraine
A. Associated Vertices 首先求出SCC然后缩点,第一次求出每个点能到的点集,第二次收集这些点集即可,用bitset加速,时间复杂度$O(\frac{nm}{64})$. #inc ...
- XVI Open Cup named after E.V. Pankratiev. GP of Peterhof
A. (a, b)-Tower 当指数大于模数的时候用欧拉定理递归计算,否则直接暴力计算. #include<cstdio> #include<algorithm> #incl ...
随机推荐
- web项目没有run on server时..
文章转载至:http://blog.csdn.net/hongchangfirst/article/details/7722703 web项目没有run on server 1.首先确保正确安装Tom ...
- jq 全选和反选以及判断那条被选中
<body><div><input type="checkbox" id="a" />全选</div><d ...
- Android自学指导
如果想自学Android,以下的文章可以作为参考: 如何自学Android(Gityuan) 那两年炼就的Android内功修养(老罗的Android之旅)
- Notice: Only variable references should be returned by reference(PHP版本兼容性问题)
摘自:http://sushener.spaces.live.com/blog/cns!BB54050A5CFAFCDD!435.entry PHP5一个很让人恼火的一点就是BC(向后兼容)不是很理想 ...
- 重温WCF之会话Session(九)
转载地址:http://blog.csdn.net/tcjiaan/article/details/8281782 每个客户端在服务器上都有其的独立数据存储区,互不相干,就好像A和服务器在单独谈话一样 ...
- Jmeter在restful风格接口测试中的应用
1.如何下载安装 官网下载,一个压缩包apache-jmeter-3.0.zip,解压即可,打开bin目录下jmeter.bat即可打开软件. 2.熟悉界面 3.实际案例 测试restful风格接口 ...
- golang 索引
入门的基础路线 a Tour of GoEffective GoGo By Example 以上的三部分通读算是入门. 4个重要的组成部分 1. 基础知识2. 并发特性3. 异常处理4. 常用开源项目 ...
- Oracle 监听器
Oracle监听器listener是一个重要的数据库服务器组件,在整个Oracle体系结构中,扮演着重要的作用. 监听器Lisener功能 从当前的Oracle版本看,Listener主要负责下面的几 ...
- 关于cout<<ends你不知道的那些事
关于ends是C++中比较基础的一个东西,但是可能不是每个人都能够清楚的理解这是个什么东西,我就经历了这么一个过程,写出来让大家看看,有什么理解的不对的地方欢迎拍砖. 今天以前我对ends的理解是:输 ...
- sql语句中----删除表数据的"三兄弟"
说到删除表数据的关键字,大家记得最多的可能就是delete了 然而我们做数据库开发,读取数据库数据.对另外的两兄弟用得就比较少了 现在来介绍另外两个兄弟,都是删除表数据的,其实也是很容易理解的 老大- ...