zoukankan      html  css  js  c++  java
  • [NOIP2017]逛公园

    题目:洛谷P3953、Vijos P2030、UOJ#331。

    题目大意:
    给你(N)点(M)边的有向无权图,没有负权但有零权。求(1)到(N)的路径中长度不超过(d+K)的路径的条数(mod P),无穷输出(-1)。
    解题思路:
    考场上我写的貌似接近正解的dp,只是先判了零环,然后传递值的时候比较暴力,疯狂优化常数后拿了70分。
    正解也是dp。
    设(f_{i,j})表示到(i)号点,比最短路径多(j)的路径条数,(d_i)表示到(i)的最短路径长度。
    则(f_{i,j}=sum f_{p,d_p-d_i-e+j} )((e)为(p)到(i)的一条边权长,且({p,d_p-d_i-e+j}geqslant 0))
    边界(f_{0,0}=1)(需要加一条(0)到(1)的零边并作为起点,否则样例的零环会挂)。
    我们可以用记忆化搜索计算(f),当状态({i,j})出现了两次,则一定出现了零环,退出输出(-1)即可。
    时间复杂度貌似有点玄学,但还是过了(最坏(O(NK^2))?)。

    C++ Code:

    #include<bits/stdc++.h>
    #define M 200005
    #define N 100005
    inline int readint(){
    	int c=getchar(),d=0;
    	for(;!isdigit(c);c=getchar());
    	for(;isdigit(c);c=getchar())
    	d=(d<<3)+(d<<1)+(c^'0');
    	return d;
    }
    struct edge{
    	int to,dis,nxt;
    }e[M],e2[M];
    int head[N],head2[N],n,m,k,p,cnt1,cnt2,dis[N],l,r,q[130005];
    int dp[N][52];
    bool vis[N],ur[N][52],ok;
    inline int add1(const int u,const int v,const int t){
    	e[++cnt1]=(edge){v,t,head[u]};
    	head[u]=cnt1;
    }
    inline int add2(const int u,const int v,const int t){
    	e2[++cnt2]=(edge){u,t,head2[v]};
    	head2[v]=cnt2;
    }
    int dfs(int u,int k){
    	if(~dp[u][k])return dp[u][k];
    	dp[u][k]=0,ur[u][k]=1;
    	for(int i=head2[u];i!=-1&&ok;i=e2[i].nxt){
    		int v=e2[i].to;
    		int d=dis[u]-dis[v]-e2[i].dis+k;
    		if(d<0)continue;
    		if(ur[v][d]){
    			ok=0;return 0;
    		}
    		dp[u][k]=(dp[u][k]+dfs(v,d))%p;
    	}
    	ur[u][k]=0;
    	return dp[u][k];
    }
    int main(){
    	for(int T=readint();T--;){
    		memset(head,-1,sizeof head);
    		memset(head2,-1,sizeof head2);
    		memset(e,0,sizeof e);
    		memset(e2,0,sizeof e2);
    		cnt1=cnt2=0;
    		n=readint(),m=readint(),k=readint(),p=readint();
    		while(m--){
    			int u=readint(),v=readint(),d=readint();
    			add1(u,v,d);
    			add2(u,v,d);
    		}
    		add1(0,1,0),add2(0,1,0);
    		memset(dis,0x3f,sizeof dis);
    		memset(vis,0,sizeof vis);
    		dis[0]=0;
    		l=q[1]=0,r=vis[0]=1;int u;
    		while(l!=r){
    			vis[u=q[l=l%130000+1]]=0;
    			for(int i=head[u];i!=-1;i=e[i].nxt)
    			if(dis[e[i].to]>dis[u]+e[i].dis){
    				dis[e[i].to]=dis[u]+e[i].dis;
    				if(!vis[e[i].to])vis[q[r=r%130000+1]=e[i].to]=1;
    			}
    		}
    		memset(dp,-1,sizeof dp);
    		memset(ur,0,sizeof ur);
    		ok=dp[0][0]=1;
    		int ans=0;
    		for(int i=0;i<=k&&ok;++i)ans=(ans+dfs(n,i))%p;
    		printf("%d
    ",ok?ans:-1);
    	}
    	return 0;
    }
    
  • 相关阅读:
    array_map()与array_shift()搭配使用 PK array_column()函数
    Educational Codeforces Round 8 D. Magic Numbers
    hdu 1171 Big Event in HDU
    hdu 2844 poj 1742 Coins
    hdu 3591 The trouble of Xiaoqian
    hdu 2079 选课时间
    hdu 2191 珍惜现在,感恩生活 多重背包入门题
    hdu 5429 Geometric Progression 高精度浮点数(java版本)
    【BZOJ】1002: [FJOI2007]轮状病毒 递推+高精度
    hdu::1002 A + B Problem II
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/9122787.html
Copyright © 2011-2022 走看看