HZOJ Blue

Blue:

贪心。

我们不妨给蛤定一个先后顺序,则贪心策略即从右至左每只蛤依次往最远的石子跳。

证明:

如果最右的蛤不往最远的石子跳,而是选择了一个较近的石子,那么必然会存在一个该蛤左边的蛤越过了它跳向其右边。因为每个蛤的能力是相同的,我们可以交换路线使得该贪心策略不变差。

接着用归纳法可以证明对于所有蛤该策略最优。

复杂度O( N )

各种大佬用各种方法A了这道题……ooo的sb线段树,什么set,队列啥的都用上了……貌似只有我和b哥打了网络流,(B神盖世)比我厉害用了线段树优化建边+网络流,复杂度什么都好像都说的过去,而我只是冲着那30分去的。

网络流就比较好想了,建立两个超级源点S,SS,S向SS连容量为m的边,将每个石头拆开,连容量为1的边(如果每个石头可以跳k次那网络流板erb正解),然后相距不超过d的石头连边,最大流就是答案,不过复杂度好像说不过去……

正解:

将所有的蛤(不是青蛙吗???)看作一个整体,那么每次跳都会占据一段石头,这样是最优的,而且每次青蛙都会尽量向远处跳,所以我么可以得到这样一个结论:若一只蛤在i,下次跳最远能到j,那么最多会剩下j-i+1只蛤(即把之间全占满),这样取符合条件最大值就是了。可以用单调指针实现。

 1 #include<iostream>
 2 #include<cstdio>
 3 #define LL long long
 4 #define ma(x) memset(x,0,sizeof(x))
 5 using namespace std;
 6 int T,n,m,d,l,a[1000010];
 7 signed main()
 8 {
 9     cin>>T;
10     while(T--)
11     {    
12         cin>>n>>m>>d>>l;
13         for(int i=1;i<=n;i++)cin>>a[i];
14         if(d==l){puts("Excited");continue;}
15         int ans=m;a[n+1]=l;
16         int R=0;bool pd=0;
17         for(int i=0;i<=n+1;i++)
18         {
19             while(a[R+1]-a[i]<=d&&R<n+1)R++;
20             if(R==n+1)break;
21             ans=min(ans,R-i);
22         }
23         if(ans==m)puts("Excited");
24         else cout<<ans<<endl;
25     }
26 }
和Dinic比起来短好多……
原文地址:https://www.cnblogs.com/Al-Ca/p/11331094.html