点击打开链接
UvaLive 6435 Network Packet Ordering
题意:从纽约往dublin发n个数据包,告诉你每个数据包到达的理想时间ta1,ta2.....tan,但是数据包传输的实际时间是可能比理想时间晚x毫秒,x<D,但是数据包到达的相对顺序不会改变。从雅加达向dublin发m个数据包,数据包传输过程同上。问最后dublin接收两地发来的数据包的顺序有多少种?数据包到达的时间可以为小数,但是输入的数据一定是整数。
从纽约发的数据包把时间分成了n+1个区间,分别是0-ta1,ta1-ta2,ta2-ta3.....tan-无穷大。
用dp【i】【j】表示从雅加达发来的前i个数据包,第i个数据包在区间j中答案有多少种。那么转移就是,dp【i】【j】=sum(dp【i-1】【k】,1<=k<=j)。但是这样的时间复杂度和空间复杂度都太高,需要优化。首先每个数据包所在的区间不会超过200个,可以预处理出每个数据包可以在的区间,dp数组的第二维优化到200,这样空间和时间都优化下来了,仔细观察我们还可以将转移的复杂度优化到O(1),这样总时间复杂度为O(n*200*15)。详情见代码:
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #include<vector> #include<math.h> #define nn 51000 #define inff 0x3fffffff #define mod 1000000009 using namespace std; typedef long long LL; int n,m,d; int ta[nn],tb[nn]; vector<int>ve[nn]; LL dp[nn][220]; int main() { int t,i,j; int cas=1; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&m,&d); for(i=1;i<=n;i++) { scanf("%d",&ta[i]); } for(i=1;i<=m;i++) { scanf("%d",&tb[i]); } for(i=1;i<=m;i++)//预处理出每个数据包能在的区间 { ve[i].clear(); int ix=upper_bound(ta+1,ta+n+1,tb[i])-ta; ve[i].push_back(ix); for(j=ix;j<=n;j++) { if(ta[j]-tb[i]<d) { ve[i].push_back(j+1); } else break; } for(j=ix-1;j>=1;j--) { if(tb[i]-ta[j]<d) { ve[i].push_back(j); } else break; } sort(ve[i].begin(),ve[i].end()); } LL sum; for(i=0;i<(int)ve[1].size();i++) { dp[1][i]=1; } for(i=2;i<=m;i++) { int id=0; sum=0; for(j=0;j<(int)ve[i].size();j++) { for(;id<(int)ve[i-1].size();id++) { if(ve[i-1][id]>ve[i][j]) break; sum=(sum+dp[i-1][id])%mod; } dp[i][j]=sum; } } LL ans=0; for(j=0;j<(int)ve[m].size();j++) ans=(ans+dp[m][j])%mod; printf("Case #%d: %lld\n",cas++,ans); } return 0; }