题意: n个城市环形连接,初始有c的钱,每到i城市,会获得a[i]的金钱,失去b[i]的金钱,问能否走遍这n个城市,且过程中金钱不为负数,输出起始城市,如果答案有多个,输出最小的数字。
思路:a[i]-b[i]的值就是到达第i个城市的金钱变化,最开始想到暴力枚举起点城市,模拟后续到其他城市的金钱变化,出现负数就break。但是,100个样例,1e6的数据,总共1e8的数据,感觉如果直接暴力的话,一定会超时,所以果断放弃。接下来便想着只用一重循环就可以解决问题,考虑了很久,发现可以用尺取法优化,但还是wa了。
总结:赛后看题解的时候,暴力可以过,数据太水了。虽然如此,但正确的打开方式是:双端队列 + 尺取法。
双端队列:https://blog.csdn.net/caicai_zju/article/details/49227927
以下附上两种代码:
1.暴力
#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 ",i); else printf("-1 "); } }
2.双端队列+尺取法
1 #include<bits/stdc++.h> 2 #define MAX 2000010 3 using namespace std; 4 typedef long long ll; 5 6 ll a[MAX],b[MAX]; 7 deque<int> q; 8 9 int main() 10 { 11 int t,n,i,j; 12 ll x; 13 scanf("%d",&t); 14 while(t--){ 15 scanf("%d%lld",&n,&x); 16 for(i=1;i<=n;i++){ 17 scanf("%lld",&a[i]); 18 } 19 for(i=n+1;i<=n+n;i++){ 20 a[i]=a[i-n]; 21 } 22 for(i=1;i<=n;i++){ 23 scanf("%lld",&b[i]); 24 } 25 for(i=n+1;i<=n+n;i++){ 26 b[i]=b[i-n]; 27 } 28 while(q.size()){ 29 q.pop_back(); 30 } 31 int f=0; 32 for(i=1;i<=n+n;i++){ 33 if(x+a[i]-b[i]>=0){ 34 x+=a[i]-b[i]; 35 q.push_back(i); 36 if(q.size()>=n){ 37 printf("%d ",q.front()); 38 f=1; 39 break; 40 } 41 } 42 else{ 43 while(x+a[i]-b[i]<0&&q.size()){ 44 x-=a[q.front()]-b[q.front()]; 45 q.pop_front(); 46 } 47 if(x+a[i]-b[i]>=0){ 48 x+=a[i]-b[i]; 49 q.push_back(i); 50 if(q.size()>=n){ 51 printf("%d ",q.front()); 52 f=1; 53 break; 54 } 55 } 56 } 57 } 58 if(f==0) printf("-1 "); 59 } 60 return 0; 61 }