2018 ICPC Asia Beijing Regional Contest 北京網路賽D. 80 Days
阿新 • • 發佈:2018-12-11
北京網路賽我們隊只做出了這道題。賽後學校將現場賽隊伍進行了調整,其中兩個能穩穩參加現場賽的隊伍發揮很不好,一個爆零一個差點爆零,錯失最後一次機會。我們隊雖然之前也拿過一次倒一拿過一次倒三,但是憑藉其它場次前十名的穩定發揮,讓已經跌倒谷底的平均排名緩緩上升,再加上北京網賽的順利一A,以女隊身份拿到最後一個確定的南京站名額(雖然很想去北京)。“可怕”的北京網賽。總結一下,有另外兩位隊友的貢獻和配合,再加上不因為曾經的重大失誤而放棄之後的比賽,是我們最後獲得穩定名額的原因。小菜雞以後要多努力,不要讓自己再處於這種危險的緊急邊緣了。
題意:
n個城市環形連線,初始有c的錢,每到i城市,會獲得a[i]的金錢,失去b[i]的金錢,問能否走遍這n個城市,且過程中金錢不為負數,輸出起始城市,如果答案有多個,輸出最小的數字。
思路:
a[i]-b[i]的值就是到達第i個城市的金錢變化。最開始想到暴力列舉起點城市,模擬後續到其他城市的金錢變化,出現負數就break,但是100個樣例,1e6的資料,總共1e8的資料感覺一定會超時,於是20分鐘寫好的暴力程式碼就放在那了,不敢交。之後參考https://blog.csdn.net/ac_0_summer/article/details/47074001 用單調佇列做的。1A。(感謝小寶貝的搜題能力)
賽後發現單調佇列246ms和暴力532ms都能過。。。資料太水
附上兩種程式碼:
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> using namespace std; int a[2000009]; int q[1000010]; int n; int head,rear; void pushq(int i) { while(head<=rear&&a[q[rear]]>=a[i]) rear--; q[++rear]=i; } void popq(int i) { while(q[head]<i-n+1) head++; } int main() { int t;cin>>t; while(t--) { head=0;rear=-1; int c,flag=0; scanf("%d%d",&n,&c); long long sum=0; for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) { int kk;scanf("%d",&kk); a[i]-=kk; a[i+n]=a[i]; } for(int i=1;i<=2*n;i++) a[i]+=a[i-1]; //for(int i=1;i<=2*n;i++) cout<<a[i]<<" "; cout<<endl; for(int i=1;i<n;i++) pushq(i); int i; for(i=n;i<2*n;i++){ pushq(i); popq(i); if(a[q[head]]-a[i-n]>=-c){ flag=1; break; } } if(flag) printf("%d\n",i-n+1); else printf("-1\n"); } }
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; int a[2000009]; int main() { int t;cin>>t; while(t--) { int n,c,flag=0; scanf("%d%d",&n,&c); long long sum=0; for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) { int kk;scanf("%d",&kk); a[i]-=kk; a[i+n]=a[i]; } // for(int i=1;i<=n;i++) cout<<a[i]<<endl; int i; for(i=1;i<=n;i++){ int j; for(j=0;j<n;j++){ sum+=a[j+i]; if(c+sum<0) break; } if(j==n) {flag=1;break;} else sum=0; } if(flag) printf("%d\n",i); else printf("-1\n"); } }