POI題目選做
阿新 • • 發佈:2020-11-20
POI題目選做
[POI2015]WIL-Wilcze doły
題意
給定一個長度為 n 的序列,你有一次機會選中一段連續的長度不超過 d 的區間,將裡面所有數字全部修改為 0。請找到最長的一段連續區間,使得該區間內所有數字之和不超過 p。
題解
顯然長度為D時只會更優,尺取法列舉,單調佇列維護被刪除的一段
#include<bits/stdc++.h> using namespace std; #define LL long long inline LL read() { LL f = 1,x = 0; char ch; do { chView Code= getchar(); if(ch == '-') f = -1; }while(ch < '0'||ch > '9'); do { x = (x<<3) + (x<<1) + ch - '0'; ch = getchar(); }while(ch >= '0'&&ch <= '9'); return f*x; } const int MAXN = 2000000 + 5; LL n,p,d; LL sum[MAXN],a[MAXN]; LL ans; LL q[MAXN],head= 1,tail; inline LL calc(LL x) { return sum[x] - sum[x-d]; } int main() { n = read(),p = read(),d = read(); for(int i=1;i<=n;i++) a[i] = read(),sum[i] = sum[i-1] + a[i]; ans = d; q[++tail] = d; int l = 1; for(int i=d+1;i<=n;i++) { while(head <= tail && calc(i) > calc(q[tail])) tail--; q[++tail] = i; while(head <= tail && sum[i] - sum[l-1] - calc(q[head]) > p) { l++; while(head <= tail && l >q[head] - d + 1) head++; } ans = max(ans, 1LL * i - l + 1); } cout << ans << endl; }
[POI2012]LIT-Letters
題意
給出兩個長度相同的的只含大寫字母的字串 a,b
每次可以交換相鄰字元,求a到b的最小交換次數
題解
火柴排隊弱化版?
顯然逆序對
#include<bits/stdc++.h> using namespace std; #define LL long long inline LL read() { LL f = 1,x = 0; char ch; do { ch = getchar(); if(ch == '-') f = -1; }while(ch < '0'||ch > '9'); do { x = (x<<3) + (x<<1) + ch - '0'; ch = getchar(); }while(ch >= '0'&&ch <= '9'); return f*x; } const int MAXN = 1000000 + 5; int n; char s[MAXN]; int a[MAXN]; queue<int>Q[30]; LL c[MAXN]; inline int lowbit(int x) { return x&(-x); } inline LL Query(LL x) { LL res = 0; while(x) { res += c[x]; x -= lowbit(x); } return res; } inline void update(int x,int v) { while(x <= n) { c[x] += v; x += lowbit(x); } } int main() { n = read(); scanf("%s",s+1); for(int i=1;i<=n;i++) a[i] = s[i] - 'A'; scanf("%s",s+1); for(int i=1;i<=n;i++) Q[s[i] -'A'].push(i); for(int i=1,cur;i<=n;i++) cur = a[i],a[i] = Q[cur].front(),Q[cur].pop(); LL ans = 0; for(int i=1;i<=n;i++) { ans += i - 1 - Query(a[i]); update(a[i],1); } cout << ans << endl; }View Code