AtCoder Beginner Contest 212 E - Safety Journey (DP)
-
题意:一张\(n\)个点的完全图,删去\(m\)条边,一共走\(k\)步,问你从起点出发再回到起点一共有多少种方案?
-
题解:设\(dp[i][j]\)表示走了\(i\)步,以\(j\)为终点的方案数,那么状态转移为\(dp[i+1][u]=\sum_{v\in edge[u]} dp[i][v]\).
此时的代码为(注意此时的\(edge\)表示连着的边):
for(int i=0;i<k;++i){ for(int u=1;u<=n;++u){ for(auto v:edge[u]){ dp[i+1][u]+=dp[i][v]; } } }
因为是完全图,所以时间复杂度为\(O(k*n^2)\).
但题目给的是删去的边,我们可以将原方程转化一下(此时的\(edge\)表示删去的边):\(dp[i+1][u]=\sum_{v=1}^{n}dp[i][v]-\sum _{v\in edge[u]}dp[i][v]\).因为删去的边最多只有\(5000\)条,所以此时的时间复杂度为\(O((n+m)*k)\).
-
代码:
#include <bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define me memset #define rep(a,b,c) for(int a=b;a<=c;++a) #define per(a,b,c) for(int a=b;a>=c;--a) const int N = 1e6 + 10; const int mod =998244353; const int INF = 0x3f3f3f3f; using namespace std; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll lcm(ll a,ll b) {return a/gcd(a,b)*b;} int n,m,k; vector<int> edge[N]; ll dp[5005][5005]; int main() { scanf("%d %d %d",&n,&m,&k); for(int i=1;i<=m;++i){ int u,v; scanf("%d %d",&u,&v); edge[u].pb(v),edge[v].pb(u); } dp[0][1]=1; for(int i=0;i<k;++i){ ll sum=0; for(int j=1;j<=n;++j) sum=(sum+dp[i][j]+mod)%mod; for(int j=1;j<=n;++j){ dp[i+1][j]=(sum-dp[i][j]+mod)%mod; for(auto to:edge[j]){ dp[i+1][j]=(dp[i+1][j]-dp[i][to]+mod)%mod; } } } printf("%lld\n",dp[k][1]); return 0; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮