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比起来短好多……