[loj3560]From Hacks to Snitches

记$l_{x}$为经过$x$的守卫路径长度,若不存在此类守卫则定义$l_{x}=1$

注意到若能在时刻$t$到达$x$,显然也能在时刻$t+l_{x}$到达$x$(顺着守卫的方向走),因此定义$d_{x,s}$为最早到达$x$​且$\equiv s(mod\ l_{x})$的时刻,即具备单调性,进而不难得到转移如下——

$$
d_{x,s}\rightarrow
d_{y,t}=\min_{k\in N,d_{x,s}+k\cdot l_{x}+1\equiv t(mod\ l_{y})}(d_{x,s}+k\cdot l_{x}+1)
$$
其中转移需满足:1.$x=y$或$(x,y)\in E$;2.时刻$t$没有守卫经过$y$;3.时刻$t$没有守卫从$y$到$x$(注意$t$与$d_{x,s}+k\cdot l_{x}+1$等价)

在上述状态转移中,总转移数$M=\sum_{(x,y)\in E}l_{x}l_{y}\le mL+L^{4}$(对$x,y$是否均被守卫经过分类讨论),并且转移时有$d_{x,s}<d_{y,t}$,即可以使用dijkstra实现,时间复杂度为$o(M\log M)$,需要进行优化

 

具体的,将转移分为四类,分别进行优化:

1.$y$未被守卫经过,根据dijkstra的单调性,对于每一个$x$仅需要对此类$y$转移一次即可

2.$x$未被守卫经过且$y$被守卫经过,令$T$为$y$在$d_{x,s}$之后最早被守卫经过的时刻,仅转移到$d_{x,s}+1$和$T+1$即可

另外,若$d_{x,s}+1=T$则前者不能转移,正确性注意到其余的部分均会在$y$内部进行转移

3.$(x,y)$是某个守卫经过的边(包括正序和逆序),直接处理即可(注意仅需要转移$k=0$时)

4.除上述情况以外,即$x,y$均被守卫经过且不是某个守卫经过的边

令$T$为$y$在$d_{x,s}$之后最早被守卫经过的时刻,若时刻$T$没有守卫经过$x$,那么就可以在$y$上等待并在时刻$T$返回$x$(之后再返回$y$)

通过此方式,能转移到所有的$d_{y,t}$,并且已经达到下限(注意dijkstra的贪心),因此类似第2种情况转移后,就可以删除该边

进一步的,若时刻$T$有守卫经过$x$,那么对于$T$之前的时刻可以直接转移,否则必须绕若干圈后直至$T$时刻之后

记$T_{1}$为$T$以及$T$之后最早$\equiv s(mod\ l_{x})$的时刻(转到$T_{1}$时停止)$,T_{2}$为$y$在$T_{1}$之后最早被守卫经过的时刻,类似的判定时刻$T_{2}$是否有守卫经过$x$:若没有守卫经过$x$则处理方式与$T$相同(但不删除该边),否则简单分析不难证明走更多圈也无意义

 

考虑此时的$M$,将转移分为三类,分别进行分析:

1.$x,y$中某个点未被守卫经过,这类边仅会转移1次,因此总转移数为$o(m)$

2.$(x,y)$是某个守卫经过的边,这类边共$L$条且至多转移$L$次,因此总转移数为$o(L^{2})$

3.除上述情况外,即优化中的第4种情况,此时考虑$x$向环$y$的总转移数:第一次转移$ℓ_{y}$次后,至多剩下$\lceil\frac{ℓ_{y}}{l_{x}}\rceil$条边,即剩下的$l_{x}-1$个$s$转移次数均仅为$\lceil\frac{ℓ_{y}}{l_{x}}\rceil$,求和后为$ℓ_{y}+(l_{x}-1)\lceil\frac{ℓ_{y}}{l_{x}}\rceil\le 2ℓ_{y}$

再对$x$所在环上每一个点求和,最终两环之间总转移数即$o(ℓ_{x}ℓ_{y})$,求和后显然即$o(L^{2})$

综上,总转移数$M$是$o(m+L^{2})$的,而时间复杂度为$o(M\log M)$,可以通过

[loj3560]From Hacks to Snitches
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 250005
  4 #define M 5000005
  5 struct Edge{
  6     int pre,nex,fr,to;
  7 }edge[M<<1];
  8 struct Data{
  9     int x,s,d;
 10     bool operator < (const Data &k)const{
 11         return d>k.d;
 12     }
 13 };
 14 priority_queue<Data>q;
 15 int n,m,t,E,x,y,ans,head[N],l[N],bl[N],pos[N],suml[N],vis0[N],vis[M],d[M];
 16 int read(){
 17     int x=0;
 18     char c=getchar();
 19     while ((c<'0')||(c>'9'))c=getchar();
 20     while ((c>='0')&&(c<='9')){
 21         x=x*10+c-'0';
 22         c=getchar();
 23     }
 24     return x;
 25 }
 26 int id(int x,int s){
 27     return suml[x-1]+s+1;
 28 }
 29 void upd(int x,int D){
 30     int s=D%l[x];
 31     if (d[id(x,s)]>D){
 32         d[id(x,s)]=D;
 33         q.push(Data{x,s,d[id(x,s)]});
 34     }
 35 }
 36 int get_nex(int d,int l,int s){
 37     if (d%l>s)d+=l-d%l;
 38     if (d%l<s)d+=s-d%l;
 39     return d;
 40 }
 41 void add(int x,int y){
 42     edge[E]=Edge{-1,head[x],x,y};
 43     if (head[x]!=-1)edge[head[x]].pre=E;
 44     head[x]=E++;
 45 }
 46 void del(int k){
 47     if (edge[k].nex>=0)edge[edge[k].nex].pre=edge[k].pre;
 48     if (edge[k].pre<0)head[edge[k].fr]=edge[k].nex;
 49     else edge[edge[k].pre].nex=edge[k].nex;
 50 }
 51 int calc(){
 52     memset(d,0x3f,sizeof(d));
 53     upd(1,0);
 54     while (!q.empty()){
 55         int x=q.top().x,s=q.top().s,D=q.top().d;
 56         q.pop();
 57         if (vis[id(x,s)])continue;
 58         vis[id(x,s)]=1;
 59         if ((!bl[x])||((s+1)%l[x]!=pos[x]))upd(x,D+1);
 60         for(int i=head[x];i!=-1;i=edge[i].nex){
 61             int y=edge[i].to,T=get_nex(D+1,l[y],pos[y]);
 62             if (!bl[y]){
 63                 upd(y,D+1),del(i);
 64                 continue;
 65             }
 66             if (!bl[x]){
 67                 if (D+1!=T)upd(y,D+1);
 68                 upd(y,T+1);
 69                 continue;
 70             }
 71             if ((bl[x]==bl[y])&&((pos[x]+1)%l[x]==pos[y])){
 72                 upd(y,D+1);
 73                 continue;
 74             }
 75             if ((bl[x]==bl[y])&&((pos[y]+1)%l[x]==pos[x])){
 76                 if ((s!=pos[y])&&((s+1)%l[x]!=pos[y]))upd(y,D+1);
 77                 continue;
 78             }
 79             if (D+1!=T)upd(y,D+1);
 80             if (T%l[x]!=pos[x]){
 81                 upd(y,T+1),del(i);
 82                 continue;
 83             }
 84             int T1=get_nex(T,l[x],s),T2=get_nex(T1+1,l[y],pos[y]);
 85             if (T1+1!=T2)upd(y,T1+1);
 86             if (T2%l[x]!=pos[x])upd(y,T2+1);
 87         }
 88     }
 89     return d[id(n,0)];
 90 }
 91 int main(){
 92     n=read(),m=read();
 93     memset(head,-1,sizeof(head));
 94     for(int i=1;i<=m;i++){
 95         x=read(),y=read();
 96         add(x,y),add(y,x);
 97     }
 98     t=read();
 99     for(int i=1;i<=n;i++)l[i]=1;
100     for(int i=1;i<=t;i++){
101         x=read();
102         for(int j=0;j<x;j++){
103             y=read();
104             l[y]=x,bl[y]=i,pos[y]=j;
105         }
106     }
107     for(int i=1;i<=n;i++)suml[i]=suml[i-1]+l[i];
108     ans=calc();
109     if (ans!=0x3f3f3f3f)printf("%d\n",ans);
110     else printf("impossible\n");
111     return 0;
112 }
View Code

 

上一篇:python:发送消息给微信企业号


下一篇:favicon.ico图标在谷歌浏览器好好的可以显示,在edge却不行,已解决