如果Sum{[l,r]}<=P,那麼對於所有的l<=x<=r,Sum{[x,r]}也會<=P
如果Sum{[l,r]}>P,那麼對於所有的1<=x<=l(一個是數字一個是字母別搞混XD),Sum{[x,r]}也會>P
因此我們可以考慮枚舉r,找出最小的l,那麼結尾為r的合法區間數量就是r-l+1了
可以考慮二分搜這個l,複雜度O(NlogN)
不過這裡提供單調對列O(N)的作法
仔細想想可以發現,最小的l在r慢慢增加時不會變小
因此可以用雙指標由左而右掃過去,右指標每增加1就把左指標往右移直到區間合法為止(有可能不需移動)
具體實作可以用queue<int>存前綴和
也不知道還有甚麼BUG,真正的結果要等比賽結束才會知道Orz
ps.最後四題全對耶真開心 :D
code:
可以考慮二分搜這個l,複雜度O(NlogN)
不過這裡提供單調對列O(N)的作法
仔細想想可以發現,最小的l在r慢慢增加時不會變小
因此可以用雙指標由左而右掃過去,右指標每增加1就把左指標往右移直到區間合法為止(有可能不需移動)
具體實作可以用queue<int>存前綴和
也不知道還有甚麼BUG,真正的結果要等比賽結束才會知道Orz
ps.最後四題全對耶真開心 :D
code:
#include<cstdio> #include<cassert> #include<queue> #define scanf(x,...) assert(scanf(__VA_ARGS__)==x) using namespace std; int N,P; int main() { freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); int testcase;scanf(1,"%d",&testcase); while(testcase--) { scanf(2,"%d%d",&N,&P); long long sum=0LL; queue<int>q; q.push(sum); long long ans=0LL; for(int i=0,v;i<N;i++) { scanf(1,"%d",&v); q.push(sum+=v); while(q.front()<sum-P)q.pop(); // printf("sz=%d\n",(int)q.size()); ans+=(long long)q.size()-1LL; } static int kase=1; printf("Case #%d: %lld\n",kase++,ans); } scanf(-1,"%d",&testcase); return 0; }
沒有留言:
張貼留言
歡迎留言或問問題~
若您的留言中包含程式碼,請參考這篇
如果留言不見了請別慌,那是因為被google誤判成垃圾留言,小莫會盡快將其手動還原
注意:只有此網誌的成員可以留言。