Gym 100801 J. Journey to the "The World's Start" DP + Monotonic Queue Optimization + Two Points

   http://codeforces.com/gym/100801

The main idea of ​​the title: There are n stations from left to right, there are n-1 kinds of tickets, the i-th ticket can take i stations at most at one time (1<=i<=n) Each ticket has a fixed price p[i] , you can continue to get on the bus after getting off the bus, but it takes a certain time v[i] to get on the bus every time you get off the bus. It does not take time to get on the bus at the 1st and nth stations. It takes 1 minute. You can only buy one kind of ticket, and ask what is the lowest fare for all the plans that can go from the 1st station to the nth station within the time t.

Problem- solving ideas: 
The key to this problem is how to find the minimum time required for each ticket to arrive at the end. If you find the minimum time for each ticket to reach the station, you can directly judge which ticket is the cheapest.

For finding the time of each ticket, the most intuitive idea is to perform dp on each ticket, let dp[i] be the minimum time required to get to station i, k is the maximum number of stations the ticket can take, and v[i] ] is the time to get off and get on the train at this station. 
dp[i]=min(dp(ij))+v[i] 1<=j<=ik 
For n-1 kinds of tickets, each ticket enumerates n stations, and when enumerating to each station, ask Push forward k, the complexity is O(n^3)

But we will find that if you take a ticket for n stations, you can arrive within t time. Then a ticket for n+1 stations can also arrive within t time. In this way, we can binary search for the ticket with the least number of stations among the tickets whose time is less than or equal to t-(n-1). (The demarcation line of tickets that can be reached within the specified time) The complexity of n^2*logn will still time out

For each dp, we observe the state equation and find that the best state is to find the minimum value in the interval of dp[ij](1<=j<=ik), and each search time is o(k). In fact, we can maintain a monotonic queue of length k to find the minimum value. Complexity o(n*logn), solve.

AC code

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 1e5+10 ,mod = 998244353,inf=0x3f3f3f3f;
 4 const double pi=acos(-1.0);
 5 typedef long long ll;
 6 ll dp[maxn];
 7 ll p[maxn],v[maxn],n,m;
 8 struct node
 9 {
10     ll val,pos;
11 }q[maxn];
12 ll solve(ll k)
13 {
14     memset(dp,inf,sizeof(dp));
15     ll head=1,tail=0;
16     for(ll i=1;i<=k;i++)   //前k个的最优解就是v[i]
17     {
18         dp[i]=v[i];
19         while(head<=tail&&dp[i]<=q[tail].val)tail--;
20         q[++tail].val=dp[i],q[tail].pos=i;
21     }
22     //cout<<tail<<endl;
23     for(ll i=k;i<=n;i++)   
24     {
25         while(i-q[head].pos>k)head++; //Note the subscript range
 26          dp[i]=min(dp[q[head].pos]+ v[i],dp[i]);
 27          while (head<=tail&&dp[i]<=q[ tail].val)tail-- ; // maintain monotonicity
 28          q[++tail].val=dp[i],q[tail].pos= i;
 29         // for(int j=1;j< =k;j++) //code before unoptimized
 30         // {
 31         //      if(ij>0)
 32         //      dp[i]=min(dp[ij]+v[i],dp[i]);
 33         // } 
34      }
 35      return dp[n];
 36  }
 37  int main()
 38  {
 39     freopen("journey.in","r",stdin);    //交题要用到文件流
40     freopen("journey.out","w",stdout);
41     scanf("%lld %lld",&n,&m);
42     for(ll i=1;i<=n-1;i++)
43         scanf("%lld",&p[i]);
44     v[1]=v[n]=0;
45     for(ll i=2;i<=n-1;i++)
46         scanf("%lld",&v[i]);
47     m-=n-1;
48     ll l=1,r=n-1;
49     while(l<=r)   //二分
50     {
51         ll mid=(l+r)/2;
52         if(solve(mid)>m)
53             l=mid+1;
54         else
55             r=mid-1;
56     }
 57      ll ans= inf;
 58      for (ll i=l;i<=n- 1 ;i++ ) //find the dividing point and find the minimum value from the right interval
 59      {
 60          ans= min(ans,p[i]);
 61      }
 62      printf( " %lld\n " ,ans);
 63 }

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325344956&siteId=291194637