[NOIP2017] 逛公园

嘟嘟嘟

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

好吧,说正事。

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

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

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

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

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

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

扫描二维码关注公众号,回复: 3270782 查看本文章
  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

猜你喜欢

转载自www.cnblogs.com/mrclr/p/9686834.html