题意:n 是一圈内的数字(a1,a2,,,an)个数,p 步数的上限,问初始值 ans 最小是多少时,ans+a1+a2+…能大于等于 g。(其中 n 个数构成一个圆圈,要求走的步数不超过 p)
二分答案。然后讨论
- 一圈增量小于等于 0 时,直接模拟到 min(2n,p)将最大值与 g 比较。
因为比如-10 100 -10 这组数据前两圈的最大值出现在第二圈。
2.增量大于 0 时,圈数 a1 = p/n,同样模拟两圈,之后的计算就可以。
加了输入挂,优化二分后从 T 变 WA 了。。挖坑以后补。。
话说谷歌的思路题好变态。。。
有好想法的聚聚可以在下面留言互相交流。
也就是说这是一份 WA 的代码。。。目前只理论 AC。。(雾
但是整体的思路应该是正确的,细节太多。。。
#include<cstring> #include<cstdio> #include<cstring> #include<cmath> #include<string> #include<iostream> #include<algorithm> using namespace std; long long a[100005]; long long sum[100005]; //前缀和 long long maxx[100005]; //前i个数中前缀和最大的角标 long long n, g, p, ans, a1, b1, cnt; long long x1; //x1是模拟两圈后的结果,作为第三圈的初始值 long long liz; //sum最小值 long long da; //模拟过程中的最大值 template <class T> //输入挂 inline bool scan_d(T &ret) { char c; int sgn; if(c=getchar(),c==EOF) return 0; //EOF while(c!='-'&&(c<'0'||c>'9')) c=getchar(); sgn=(c=='-')?-1:1; ret=(c=='-')?0:(c-'0'); while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0'); ret*=sgn; return 1; } bool judge1(long long x){ long long k = min(2*n,p); da = x; for(int i = 1; i <= k; i++){ if(x >= g) return 1; long long qq = i%n; if(qq == 0) qq = n; x += a[qq]; if(x < 0) x = 0; da = max(da, x); if(i == k){ x1 = x; if(x >= g) return 1; return 0; } } } bool judge2(long long x){ cnt = a1-2; bool flag = judge1(x); long long ret = x1; if(p <= 2*n) return flag; else{ ret += cnt*sum[n]; if(sum[maxx[b1]] > 0) ret += sum[maxx[b1]]; } da = max(ret, da); if(da >= g) return 1; return 0; } long long cal1(){ //增量小于等于0 long long l = 0, r = g; bool k; while(l <= r){ //cout << "l: " << l << "r: " << r << endl; long long mid = l+(r-l)/2; if(judge1(mid)) r = mid-1; //else l = mid+1; else { //优化二分 if(mid < liz) l = mid+1; else l = mid+g-da; } } return l; } long long cal2(){ //增量大于0 long long l = 0, r = g; bool k; while(l <= r){ //cout << "l: " << l << "r: " << r << endl; long long mid = l+(r-l)/2; if(judge2(mid)) r = mid-1; //else l = mid+1; else{ //优化二分 if(mid < liz) l = mid+1; else l = mid+g-da; } } return l; } int main(){ //freopen("a.txt", "r", stdin); int t; scanf("%d", &t); for(int cas = 1; cas <= t; cas++){ sum[0] = 0; a[0] = 0; maxx[0] = 0; liz = 0; scan_d(n);scan_d(g);scan_d(p); //scanf("%lld %lld %lld", &n, &g, &p); a1 = p/n; //quan b1 = p%n; // th. long long mx = -1e18, k = 0; for(int i = 1; i <= n; i++){ //scanf("%lld", &a[i]); scan_d(a[i]); sum[i] = sum[i-1]+a[i]; liz = min(liz, sum[i]); if(sum[i] > mx){ mx = sum[i]; maxx[i] = i; k = i; }else{ maxx[i] = k; } //mx = max(sum[i], sum[i-1]); } // for(int i = 1; i <= n; i++) cout << sum[i] <<" "; //cout << endl; //cout << liz << endl; //for(int i = 0; i < u; i++) cout << fu[i] << endl; //cout << a1 << b1 << endl; if(sum[n] <= 0) ans = cal1(); else{ liz = -liz; // cnt = a1-2; ans = cal2(); } //ans = cal(); printf("Case #%d: %lldn", cas, ans); } return 0; }