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;
}