NOI.AC NOIP模擬賽 第一場 補記
阿新 • • 發佈:2018-09-21
沒有 利用 選擇 基準 main check long 並排 sdi
NOI.AC NOIP模擬賽 第一場 補記
candy
題目大意:
有兩個超市,每個超市有\(n(n\le10^5)\)個糖,每個糖\(W\)元。每顆糖有一個愉悅度,其中,第一家商店中的第\(i\)顆糖果的愉悅度為\(A_i\),而第二家商店中的第\(i\)顆糖果的愉悅度為\(B_i\)。
在每家商店買的糖果會被打包到一個袋子中(可以在一家商店什麽都不買,此時認為這家商店的袋子為空)。因為這兩個袋子外觀是一樣的,所以會從兩個袋子中隨機選擇一個,然後吃光裏面的糖果。定義一種買糖果的方案的愉悅度為:吃到的糖果的愉悅度之和的最小可能值。
求買糖果的愉悅度與買糖果的花費之差的最大值。
思路:
顯然對於一家店,購買相同數量的糖果,一定選擇愉悅度盡量高的更優。
因此將\(A_i\)和\(B_i\)從大到小排序,求前綴和。答案就是\(\max\{\min(A_i,B_j)-(i+j)W\}\)。枚舉每一個\(A_i,B_j\)作為\(\min\),然後另一個數就可以通過二分求出來。
時間復雜度\(\mathcal O(n\log n)\)。
源代碼:
#include<cstdio> #include<cctype> #include<algorithm> inline int getint() { register char ch; while(!isdigit(ch=getchar())); register int x=ch^'0'; while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); return x; } typedef long long int64; const int N=1e5+1; int64 a[N],b[N]; int main() { const int n=getint(),m=getint(); for(register int i=1;i<=n;i++) a[i]=getint(); for(register int i=1;i<=n;i++) b[i]=getint(); std::reverse(&a[1],&a[n]+1); std::reverse(&b[1],&b[n]+1); for(register int i=1;i<=n;i++) a[i]+=a[i-1]; for(register int i=1;i<=n;i++) b[i]+=b[i-1]; int64 ans=0; for(register int i=0;i<=n;i++) { const int j=std::lower_bound(&b[0],&b[n]+1,a[i])-b; if(j<=n) ans=std::max(ans,a[i]-(int64)(i+j)*m); } for(register int i=0;i<=n;i++) { const int j=std::lower_bound(&a[0],&a[n]+1,b[i])-a; if(j<=n) ans=std::max(ans,b[i]-(int64)(i+j)*m); } printf("%lld\n",ans); return 0; }
sort
題目大意:
一個長度為\(n(n\le50000)\)的序列\(A\)。每次操作可以將一個區間翻轉,定義翻轉區間\([l,r]\)的代價為\(r-l+1\)。要通過翻轉將這個序列排序,請你構造出代價小小於\(2\times10^7\)的一種方案。
思路:
當\(A_i\in\{0,1\}\)時,用歸並排序的思想,每次歸並時將左子區間的後綴\(1\)與右子區間的前綴\(0\)交換即可。
而沒有\(A_i\in\{0,1\}\)的條件時,我們可以利用快速排序的思想,每次從區間內隨機選取一個數\(x\)作為基準,\(\le x\)的數作為\(0\),\(>x\)的數作為\(1\)。然後內層套用上述歸並排序的算法。
源代碼:
#include<cstdio>
#include<cctype>
#include<climits>
#include<algorithm>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int N=5e4+1;
int a[N];
inline bool check(const int &b,const int &e) {
for(register int i=b;i<e;i++) {
if(a[i]>a[i+1]) return false;
}
return true;
}
void solve(const int &b,const int &e,const int &x) {
if(b==e) return;
const int mid=(b+e)>>1;
solve(b,mid,x);
solve(mid+1,e,x);
int p=b,q=e;
while(p<=mid&&a[p]<=x) p++;
while(q>mid&&a[q]>x) q--;
if(p<=mid&&q>mid) {
printf("%d %d\n",p,q);
std::reverse(&a[p],&a[q]+1);
}
}
void solve(const int &b,const int &e) {
if(b>=e) return;
if(check(b,e)) return;
const int x=a[b+rand()%(e-b+1)];
solve(b,e,x);
for(register int i=b;i<=e;i++) {
if(a[i]>x) {
solve(b,i-1);
solve(i,e);
return;
}
}
solve(b,e);
}
int main() {
srand(998244353);
const int n=getint();
for(register int i=1;i<=n;i++) a[i]=getint();
solve(1,n);
puts("-1 -1");
return 0;
}
NOI.AC NOIP模擬賽 第一場 補記