• noip2017 逛公园


    洛谷P3953

    loj2316

    uoj331

    做题记录:

    花了3个小时写了个5K代码(如果是noip现场肯定时间不够了),本地跑大样例跑3秒一组?

    结果交上去一看70分,最慢点800ms左右,所有有0边的都错了?

    然而事实上这代码这么长大部分就是为了特判0边。。。看来即使noip发现码量不对也要尽快放弃

    下数据一测...单组数据就A了?

    调了1个小时,终于调出来了,就改了一行...

    错误记录:241行上界错误,t2[0]写成n


    自己的(假)做法:(说不定其实有错?)

    先求最短路。设d[i]表示1到i的最短路

    首先判-1。可以发现,如果存在一条从1到n过某点u的长度不超过d[n]+K的路径,且u在一个0环(由全0边组成的环)上面,就-1了,否则就不-1

    (以上可以通过再求所有点到n最短路,以及对由仅保留0边得到的图做tarjan求强连通分量完成)

    否则,考虑一个dp。an[i][j]表示到i点距离为d[i]+j的路径条数。跟最短路计数挺像。但是,可以发现转移顺序似乎有点问题?

    考虑按j来划分“层”,尽量使得转移在层间进行,避免转移成环;要保证同层内按照转移的“拓扑序”进行;显然仅当d[u] + (u,v)边的长度 = d[v]时会发生u到v的同层转移

    设(u,v)边的长度=dis(u,v)

    首先,如果没有0权边,那么显然只要按照d[i]的值从小到大将各个点排序,同层内按这个顺序转移即可。因为此时如果d[u]+dis(u,v)=d[v],那么d[u]<d[v]

    如果有0权边,就不能这么干了。

    对于任意两点u,v,它们间有边(u,v,w),如果w>0,那么仍然满足上述条件;如果w=0,那么有两种情况:

    1.d[u]>d[v];此时u到v不可能发生同层转移

    2.d[u]=d[v];此时可能发生同层内转移,因此应当保证u在v之前转移

    那么就明显了,对于d[i]相等的点,应该按照“只保留0边后的图的拓扑序中点的位置”从小到大排序

    可是似乎不一定有这个拓扑序?首先,如果有一点满足u“存在一条从1到n过u的长度不超过d[n]+K的路径”,且u在一个0环上,那么就-1了,不用dp;如果u不满足这个条件,但u在一个0环上,那么可以不管这个u

    设当且仅当'存在一条从1到n过u的长度不超过d[n]+K的路径'时,ok[u]=true;否则ok[u]=false

    所以,“只保留0边后的图的拓扑序中点的位置”应该改为“只保留0边与所有满足ok[u]=true的点u后的图的拓扑序中点的位置”

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<cstring>
      4 #include<vector>
      5 #include<queue>
      6 using namespace std;
      7 #define fi first
      8 #define se second
      9 #define pb push_back
     10 typedef long long ll;
     11 typedef unsigned long long ull;
     12 struct pii
     13 {
     14     int fi,se;
     15     pii():fi(0),se(0){}
     16     pii(int a,int b):fi(a),se(b){}
     17 };
     18 
     19 bool operator<(const pii &a,const pii &b)
     20 {
     21     return a.fi>b.fi;//||(a.fi==b.fi&&a.se<b.se);
     22 }
     23 
     24 /*
     25 bool operator>(const pii &a,const pii &b)
     26 {
     27     return a.fi<b.fi;//||(a.fi==b.fi&&a.se>b.se);
     28 }
     29 */
     30 typedef priority_queue<pii> pq;
     31 struct E
     32 {
     33     int to,d,nxt;
     34 }e[200010];
     35 int f1[100010],ne;
     36 int n,m,K,md;
     37 bool ok[100010];
     38 //inline int mul(int x,int y){return ll(x)*y%md;}
     39 //inline int add(int x,int y){return (x+y)%md;}
     40 inline void add(int &x,int y){(x+=y)%=md;}
     41 namespace OK
     42 {
     43 
     44 int dfn[100010],dfc;
     45 int s[100010],tp;
     46 int sccnum[100010],cnt;
     47 int sz[100010];
     48 int dfs(int u)
     49 {
     50     int lowu=dfn[u]=++dfc,lowv,v,k;
     51     s[++tp]=u;
     52     for(k=f1[u];k;k=e[k].nxt)
     53         if(e[k].d==0)
     54         {
     55             v=e[k].to;
     56             if(!dfn[v])
     57             {
     58                 lowv=dfs(v);
     59                 lowu=min(lowu,lowv);
     60             }
     61             else if(!sccnum[v])
     62                 lowu=min(lowu,dfn[v]);
     63         }
     64     if(lowu==dfn[u])
     65     {
     66         ++cnt;
     67         while(tp&&s[tp]!=u)    sccnum[s[tp--]]=cnt;
     68         sccnum[s[tp--]]=cnt;
     69     }
     70     return lowu;
     71 }
     72 void work()
     73 {
     74     int i;
     75     dfc=0;tp=0;
     76     memset(dfn+1,0,sizeof(dfn[0])*n);
     77     memset(sccnum+1,0,sizeof(sccnum[0])*n);
     78     memset(sz+1,0,sizeof(sz[0])*cnt);
     79     cnt=0;
     80     for(i=1;i<=n;++i)
     81         if(!dfn[i])
     82             dfs(i);
     83     for(i=1;i<=n;++i)
     84         ++sz[sccnum[i]];
     85 }
     86 
     87 }
     88 namespace Dij1
     89 {
     90 
     91 pq q;
     92 int d[100010];
     93 bool vis[100010];
     94 void dij()
     95 {
     96     int k,u,v;pii t;
     97     memset(d+1,0x3f,sizeof(d[0])*n);
     98     memset(vis+1,0,sizeof(vis[0])*n);
     99     q.push(pii(0,1));d[1]=0;
    100     while(!q.empty())
    101     {
    102         t=q.top();q.pop();
    103         u=t.se;
    104         if(vis[u])    continue;
    105         vis[u]=1;
    106         for(k=f1[u];k;k=e[k].nxt)
    107         {
    108             v=e[k].to;
    109             if(d[v]>d[u]+e[k].d)
    110             {
    111                 d[v]=d[u]+e[k].d;
    112                 q.push(pii(d[v],v));
    113             }
    114         }
    115     }
    116 }
    117 
    118 }
    119 namespace Dij2
    120 {
    121 
    122 E e[200010];
    123 int f1[100010],ne;
    124 void me(int x,int y,int z)
    125 {
    126     e[++ne].to=y;e[ne].nxt=f1[x];f1[x]=ne;e[ne].d=z;
    127 }
    128 pq q;
    129 int d[100010];
    130 bool vis[100010];
    131 void dij()
    132 {
    133     int k,u,v;pii t;
    134     memset(d+1,0x3f,sizeof(d[0])*n);
    135     memset(vis+1,0,sizeof(vis[0])*n);
    136     q.push(pii(0,n));d[n]=0;
    137     while(!q.empty())
    138     {
    139         t=q.top();q.pop();
    140         u=t.se;
    141         if(vis[u])    continue;
    142         vis[u]=1;
    143         for(k=f1[u];k;k=e[k].nxt)
    144         {
    145             v=e[k].to;
    146             if(d[v]>d[u]+e[k].d)
    147             {
    148                 d[v]=d[u]+e[k].d;
    149                 q.push(pii(d[v],v));
    150             }
    151         }
    152     }
    153 }
    154 
    155 }
    156 namespace DP
    157 {
    158 
    159 int t2[100010];
    160 namespace T
    161 {
    162 
    163 queue<int> q;
    164 int in[100010];
    165 void work()
    166 {
    167     int i,k,u;
    168     memset(in+1,0,sizeof(in[0])*n);
    169     t2[0]=0;
    170     for(i=1;i<=n;++i)
    171         if(ok[i])
    172         {
    173             for(k=f1[i];k;k=e[k].nxt)
    174                 if(ok[e[k].to]&&e[k].d==0)
    175                     ++in[e[k].to];
    176         }
    177     for(i=1;i<=n;++i)
    178         if(ok[i]&&!in[i])
    179             q.push(i);
    180     while(!q.empty())
    181     {
    182         u=q.front();q.pop();
    183         t2[++t2[0]]=u;
    184         for(k=f1[u];k;k=e[k].nxt)
    185             if(ok[e[k].to]&&e[k].d==0)
    186             {
    187                 --in[e[k].to];
    188                 if(!in[e[k].to])    q.push(e[k].to);
    189             }
    190     }
    191 }
    192 
    193 }
    194 int ps[100010];
    195 int t1[100010];
    196 using Dij1::d;
    197 bool c1(int a,int b)
    198 {
    199     return d[a]<d[b]||(d[a]==d[b]&&ps[a]<ps[b]);
    200 }
    201 int an[100010][51];
    202 namespace E2
    203 {
    204 
    205 E e[200100];
    206 int f1[100010],ne;
    207 void me(int x,int y,int z)
    208 {
    209     e[++ne].to=y;e[ne].nxt=f1[x];f1[x]=ne;e[ne].d=z;
    210 }
    211 void work()
    212 {
    213     int i,j,k,u,v,y;
    214     //printf("1t%d
    ",t1[1]);
    215     an[1][0]=1;
    216     for(j=0;j<=K;++j)
    217     {
    218         for(i=1;i<=t1[0];++i)
    219         {
    220             u=t1[i];
    221             for(k=f1[u];k;k=e[k].nxt)
    222             {
    223                 v=e[k].to;
    224                 if(d[u]+j+e[k].d<=d[v]+K)
    225                 {
    226                     y=d[u]+j+e[k].d-d[v];
    227                     add(an[v][y],an[u][j]);
    228                 }
    229             }
    230         }
    231     }
    232 }
    233 
    234 }
    235 void dp()
    236 {
    237     int i,j,k;
    238     memset(an+1,0,sizeof(an[0])*n);
    239     memset(ps+1,0,sizeof(ps[0])*n);
    240     T::work();
    241     for(i=1;i<=t2[0];++i)//
    242         ps[t2[i]]=i;
    243     t1[0]=0;
    244     for(i=1;i<=n;++i)
    245         if(ok[i])
    246             t1[++t1[0]]=i;
    247     sort(t1+1,t1+t1[0]+1,c1);
    248     memset(E2::f1+1,0,sizeof(E2::f1[0])*n);
    249     E2::ne=0;
    250     for(i=1;i<=n;++i)
    251         if(ok[i])
    252         {
    253             for(k=f1[i];k;k=e[k].nxt)
    254                 if(ok[e[k].to])
    255                 {
    256                     E2::me(i,e[k].to,e[k].d);
    257                 }
    258         }
    259     E2::work();
    260     int ans=0;
    261     for(j=0;j<=K;++j)
    262         add(ans,an[n][j]);
    263     printf("%d
    ",ans);
    264 }
    265 
    266 }
    267 /*
    268 namespace DP
    269 {
    270 
    271 queue<int> q;
    272 using Dij::d;
    273 //点的定义:(i,j)表示从1走d[i]+j的距离到i
    274 int an[100010][51];//an[i][j]表示到(i,j)的路径条数
    275 bool vis[100010][51];
    276 void dp()
    277 {
    278     memset(vis+1,0,sizeof(vis[0])*n);
    279     memset(an+1,0,sizeof(an[0])*n);
    280     int x,u,v;
    281     while(!q.empty())
    282     {
    283         u=q.front();q.pop();
    284         for(k=f1[u];k;k=e[k].nxt)
    285         {
    286             v=e[k].to;
    287             if(d[u]+e[k].d<=d[v]+K)
    288             {
    289                 y=d[u]+e[k].d-d[v];
    290                 add(an[v][y],an[u][x]);
    291             }
    292         }
    293     }
    294     for(j=1;j<=K;++j)
    295     {
    296         
    297         while(!q.empty())
    298         {
    299             t=q.front();q.pop();
    300             u=t.fi;x=t.se;
    301             for(k=f1[u];k;k=e[k].nxt)
    302             {
    303                 v=e[k].to;
    304                 if(d[u]+x+e[k].d<=d[v]+K)
    305                 {
    306                     y=d[v]+K-d[u]-x-e[k].d;
    307                     add(an[v][y],an[u][x]);
    308                 }
    309             }
    310         }
    311 }
    312 
    313 }
    314 */
    315 int T;
    316 int main()
    317 {
    318     //freopen("/tmp/test1.in","r",stdin);
    319     //freopen("/tmp/park6.in","r",stdin);
    320     //freopen("/tmp/ex_park2.out","w",stdout);
    321     int i,x,y,z;
    322     scanf("%d",&T);
    323     while(T--)
    324     {
    325         scanf("%d%d%d%d",&n,&m,&K,&md);
    326         memset(f1+1,0,sizeof(f1[0])*n);
    327         memset(ok+1,0,sizeof(ok[0])*n);
    328         ne=0;
    329         memset(Dij2::f1+1,0,sizeof(Dij2::f1[0])*n);
    330         Dij2::ne=0;
    331         for(i=1;i<=m;++i)
    332         {
    333             scanf("%d%d%d",&x,&y,&z);
    334             e[++ne].to=y;e[ne].nxt=f1[x];f1[x]=ne;e[ne].d=z;
    335             Dij2::me(y,x,z);
    336         }
    337         OK::work();
    338         Dij1::dij();Dij2::dij();
    339         {
    340             int *d1=Dij1::d,*d2=Dij2::d;
    341             for(i=1;i<=n;++i)
    342                 if(d1[i]+d2[i]<=d1[n]+K)
    343                 {
    344                     ok[i]=1;
    345                     if(OK::sz[OK::sccnum[i]]>1)
    346                     {
    347                         puts("-1");
    348                         goto xx1;
    349                     }
    350                 }
    351         }
    352         DP::dp();
    353 xx1:;
    354     }
    355     return 0;
    356 }
    View Code

    一查题解,发现貌似只要按照上面类似的方法建一个分层图,直接对这个分层图跑拓扑排序以及判环就行了?

  • 相关阅读:
    五,系统操作命令说明
    三,linux系统的由来
    二,服务器磁盘阵列(raid)
    一服务器硬件介绍
    四,元组类型
    集合类型
    字典类型
    三,列表类型
    二,字符串类型
    一,数字类型
  • 原文地址:https://www.cnblogs.com/hehe54321/p/9859111.html
Copyright © 2020-2023  润新知