• [NOIP2017] 逛公园


    嘟嘟嘟

    时隔将近一年,我终于开始捡起去年NOIP的题了。记得当时啥也不会的我看到这题无从下手,就连暴力也没写出来。

    好吧,说正事。

    1.如果k = 0的话很好做,就是最短路计数。

    2.不过这道题允许走“冤枉路”,于是我们可以dp。考虑到每走一条边,就会对冤枉路的长度做出贡献,那么令dp[i][j]表示到节点 i ,还可以走 j 长度的冤枉路。转移就是很直观的方案数累加的转移。

    3.虽然题目保证了1可以走到n,但是不能保证所有点都能走到n,所以有一些状态是走不到的。因此,我们还要反向见图跑最短路,求出哪些点可以到达n。

    4.因为可能有环,dp顺序不好确定,那么就来一波记搜吧。(然而我几乎没写过记搜,只能现学)

    5.考虑方案数无穷的情况:其实就是存在零环,只要开一个二维标记数组,在dfs时判断从该状态出发,是否又回到这个状态就行。

    6.这题卡常啊,我使出浑身解数用上了所有卡常手段才过……

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cmath>
      4 #include<algorithm>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<cctype>
      8 #include<vector>
      9 #include<stack>
     10 #include<queue>
     11 using namespace std;
     12 #define enter puts("") 
     13 #define space putchar(' ')
     14 #define Mem(a, x) memset(a, x, sizeof(a))
     15 #define rg register
     16 typedef long long ll;
     17 typedef double db;
     18 const int INF = 0x3f3f3f3f;
     19 const db eps = 1e-8;
     20 const int maxn = 1e5 + 5;
     21 inline ll read()
     22 {
     23     ll ans = 0;
     24     char ch = getchar(), last = ' ';
     25     while(!isdigit(ch)) {last = ch; ch = getchar();}
     26     while(isdigit(ch)) {ans = (ans << 3) + (ans << 1) + ch - '0'; ch = getchar();}
     27     if(last == '-') ans = -ans;
     28     return ans;
     29 }
     30 inline void write(ll x)
     31 {
     32     if(x < 0) x = -x, putchar('-');
     33     if(x >= 10) write(x / 10);
     34     putchar(x % 10 + '0');
     35 }
     36 
     37 int n, m, k, mod;
     38 vector<int> v[maxn], c[maxn];
     39 
     40 #define pr pair<int, int>
     41 #define mp make_pair
     42 bool in[maxn];
     43 int dis1[maxn];
     44 inline void dij1(const int& s)
     45 {
     46     for(int i = 1; i <= n; ++i) dis1[i] = INF, in[i] = 0;
     47     dis1[s] = 0;
     48     priority_queue<pr, vector<pr>, greater<pr> > q;
     49     q.push(mp(dis1[s], s));
     50     while(!q.empty())
     51     {
     52         int now = q.top().second; q.pop();
     53         if(in[now]) continue;
     54         in[now] = 1;
     55         for(int i = 0; i < (int)v[now].size(); ++i)
     56         {
     57             if(dis1[v[now][i]] > dis1[now] + c[now][i])
     58             {
     59                 dis1[v[now][i]] = dis1[now] + c[now][i];
     60                 q.push(mp(dis1[v[now][i]], v[now][i]));
     61             }
     62         }
     63     }
     64 }
     65 vector<int> v2[maxn], c2[maxn];
     66 int dis2[maxn];
     67 inline void dij2(const int& s)
     68 {
     69     for(rg int i = 1; i <= n; ++i) dis2[i] = INF, in[i] = 0;
     70     dis2[s] = 0;
     71     priority_queue<pr, vector<pr>, greater<pr> > q;
     72     q.push(mp(dis2[s], s));
     73     while(!q.empty())
     74     {
     75         int now = q.top().second; q.pop();
     76         if(in[now]) continue;
     77         in[now] = 1;
     78         for(rg int i = 0; i < (int)v2[now].size(); ++i)
     79         {
     80             if(dis2[v2[now][i]] > dis2[now] + c2[now][i])
     81             {
     82                 dis2[v2[now][i]] = dis2[now] + c2[now][i];
     83                 q.push(mp(dis2[v2[now][i]], v2[now][i]));
     84             }
     85         }
     86     }
     87 }
     88 
     89 bool vis[maxn][55];
     90 int dp[maxn][55];
     91 inline int dfs(const int& now, const int& res)
     92 {
     93     if(res < 0) return 0;
     94     if(vis[now][res]) return -1;
     95     if(dp[now][res] != -1) return dp[now][res];
     96     vis[now][res] = 1;
     97     int ret = 0;
     98     if(now == n) ret++;
     99     for(rg int i = 0; i < (int)v[now].size(); ++i)
    100     {
    101         int to = v[now][i];
    102         if(dis2[to] == INF) continue;
    103         int tp = dfs(to, res - c[now][i] + dis1[to] - dis1[now]);
    104         if(tp == -1) return -1;
    105         ret += tp; if(ret > mod) ret -= mod;
    106     }
    107     dp[now][res] = ret;
    108     vis[now][res] = 0;        //别忘清零 
    109     return ret;
    110 }
    111 
    112 inline void init(const int& n)
    113 {
    114     for(rg int i = 1; i <= n; ++i)
    115     {
    116         v[i].clear(), c[i].clear();    
    117         v2[i].clear(); c2[i].clear();
    118     }
    119     for(rg int i = 1; i <= n; ++i)
    120         for(rg int j = 0; j <= k; ++j) dp[i][j] = -1, vis[i][j] = 0;
    121 }
    122 
    123 int main()
    124 {
    125     int T = read();
    126     while(T--)
    127     {
    128         n = read(); m = read(); k = read(); mod = read();
    129         init(n);
    130         for(rg int i = 1; i <= m; ++i)
    131         {
    132             int x = read(), y = read(), co = read();
    133             v[x].push_back(y); c[x].push_back(co);
    134             v2[y].push_back(x); c2[y].push_back(co);
    135         }
    136         dij1(1); dij2(n);
    137         write(dfs(1, k)); enter;
    138     }
    139     return 0;
    140 }
    View Code
  • 相关阅读:
    char 型变量中能不能存贮一个中文汉字,为什么?
    抽象类(abstract class)和接口(interface)有什么异同?
    描述一下JVM加载class文件的原理机制?
    重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?
    String和StringBuilder、StringBuffer的区别?
    此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
    是否可以继承String类?
    两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?
    laraval join 的理解
    whereHasIn方法
  • 原文地址:https://www.cnblogs.com/mrclr/p/9686834.html
Copyright © 2020-2023  润新知