前話:
為什么現在才發?
答:因為沒打比賽。
為什么要發?
答:因為我是小鳥廚子
知更鳥小姐可愛捏~
兩個人的演唱會:
一道簡單的貪心,它有策略嗎?(霧)
如果只是一個數列,我們怎么辦。
讓一個數為起點,一直把后面的合法的數加到這個段內,一直到不能加,重復操作即可,這是一個很直接的思路,那么我們證明它的正確性。
假設我們將一段內某一子序列全部劃出,并劃為單獨一段或者與后一段相連,顯然,讓它單獨成段更劣,所以考慮讓它和后一段相連是否能讓后一段的貢獻更大(就是是否可以使后一段與后面合并,減小段數),顯然,若分出一段包含一個大于后一段最大值或者小于后一段最小值的數,一定不會讓后一段更優,反而可能將后一段部分子序列變得不合法。如果包含的數都在后一段\([min,max]\)之間,對段內無影響(因為影響它的是極差,即最大值和最小值)。上述分類包含全部情況,故我們的貪心策略成立。
所以問題簡化版已經搞定,對于推廣到環上,如果你看過環形DP等類似問題,那么一定可以迅速想到解法。
復制原序列,并接在后面,然后枚舉切開環的點,每一段長度等于原序列的區間都可能貢獻答案,求最小值即可。
代碼:
#include<bits/stdc++.h>
#define I_Love_Robin 0
using namespace std;
int const N=6e7+10;
int cnt,l,r;
int a[N];
int n,m;
int pos[N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
// freopen("text.in","r",stdin);
// freopen("text.out","w",stdout);
int T;
cin>>T;
while(T--)
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) a[i+n]=a[i];
cnt=l=r=0;
while(r<=2*n)
{
int mx,mn;
mx=mn=a[l];
cnt++;
while(mx-mn<=m && r<=2*n)
{
pos[r]=cnt;
r++;
mx=max(mx,a[r]);
mn=min(mn,a[r]);
}
l=r;
}
int ans=INT_MAX;
for(int i=1;i<=n;i++)
{
ans=min(ans,pos[i+n-1]-pos[i]+1);
}
// for(int i=1;i<=2*n;i++) cerr<<pos[i]<<" ";
// cerr<<endl;
cout<<ans<<"\n";
}
return I_Love_Robin;
}
空氣蛹:
相比上題,這題思考量是有的,是一道貪心好題,為啥全是貪心
先看部分分,為什么有30%部分分是保證有空杯子?不知道,手模一下。
哦,原來直接輸出總和就行。這個不用嚴謹證明了把,直接把空杯子當做中轉直接動就行,沒想到的一看就是微信小游戲玩少了。
那我們就考慮對于所有問題直接構造空杯子,顯然讓最少和次少構造最優,輸出總和減去溢出即可。
不要忘了已經有序的情況,不然會掛慘了的
代碼:
#include<bits/stdc++.h>
#define int long long
#define I_Love_Robin 0
const int N=1e5+10;
using namespace std;
int n,m;
int a[N];
int ans;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--)
{
ans=0;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i],ans+=a[i];
bool flag=true;
for(int i=1;i<n;i++) if(a[i]>a[i+1]) flag=false;
if(flag){cout<<ans<<"\n";continue;}
sort(a+1,a+n+1);
int lose=max((a[1]+a[2])-m,0ll);
cout<<ans-lose<<"\n";
}
return I_Love_Robin;
}
使一顆心免于哀傷:
Birds are born with no shackles
Then what fetters my fate?
Blown away, the white petals
Leave me trapped in the cage.
……
Let my heart bravely spread the wings
Soaring past the night
To trace the bright moonlight~~~
豪庭,太豪庭了awa
好了好了,該切水題了,不要和流螢約會了
一道挺好的博弈論題。
我們和自己玩兩把,再手玩樣例看看,發現第一個樣例十分有啟發性(水),當只剩下一種顏色時,不需要操作就結束了,再玩第二個樣例,發現小鳥一步就贏了,即直接把一段黑棋全部拿走。由此我們發現,排除不操作就結束的欺負鳥的情況,在棋盤不出現黑白交錯擺放時,小鳥只需要一步拿走所有黑棋即可。
根據這個線索,我們繼續人格分裂一下,發現必勝態是小鳥有一段連續黑棋,而周日的白棋沒有連續段(即最長段只有一顆棋子),這時候小鳥和周日交替單顆棋子,最后一定會讓周日就剩一串連續的白棋時小鳥直接取勝。那么反過來就是必敗態。
雙方都是最優策略,所以都要創造對于自己的必勝態,發現沒有必勝態時,拿走一段連續的全部棋子顯然不優,因為這給對手創造了連續段,拿走超過一顆也不優,因為你拿的越多,你就越快出現沒有連續段的情況,所以雙方最優策略就確定了,就是每次拿走一顆棋子,直到到達某一方必勝態。
答案顯而易見,誰棋子多誰能耗死對方,數棋子即可。
注意前兩個特判
代碼:
#include<bits/stdc++.h>
#define I_Love_Robin 0
using namespace std;
int const N=1e5+10;
string a;
int n;
int main(){
int T;
cin>>T;
while(T--)
{
cin>>n;
cin>>a;
bool flag=true;
for(int i=0;i<n-1;i++)
if(a[i]!=a[i+1])
{
flag=false;
break;
}
if(flag)
{
if(a[1]=='1') cout<<"Sunday"<<"\n";
else cout<<"Robin"<<"\n";
continue;
}
int cnt=0;
for(int i=0;i<n-1;i++) if(a[i]!=a[i+1]) cnt++;
if(cnt<=2) {cout<<"Robin"<<"\n";continue;}
int s=0,r=0,i=0;
for(int i=0;i<n;i++)
{
if(a[i]=='1') r++;
else s++;
}
if(r>s) cout<<"Robin"<<"\n";
if(r<=s) cout<<"Sunday"<<"\n";
}
return I_Love_Robin;
}
結語:
這次夢熊的月賽相比之前確實簡單,當然肯定娛樂性質偏多,不是小鳥我也不會發這篇
剩下的3道還是很有難度的,不像這三道這么簡單,作者也沒時間切了,所以就算了,切了也不發了
最后,親愛的讀者,您是否認為知更鳥美貌蓋世無雙。
完結撒花~
浙公網安備 33010602011771號