CF33C Wonderful Randomized Sum 題解

博客園同步

原題鏈接

簡要題意:

你可以無限次的把該數組的一個前綴和後綴 ×1\times -1,問最終的最大序列和。

這題盲目WA了數次才知道本質

這題89個數據吊打std

CF真好啊,發現一個錯後面就不測了

下面,就以我艱辛的思維歷程來構造本篇博客。

算法一

盲猜:所有數都可以變成正數。

然後絕對值相加。

連樣例也沒測。

然後,289pts\frac{2}{89} pts. 只過了前兩個樣例,第三個就死了。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
 
inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
 
int main(){
	int n=read(),s=0; while(n--) {
		int t=read();
		s+=abs(t);
	} printf("%d\n",s);
	return 0;
}

算法二

突然發現不符合樣例!

仔細想了以下,嗯嗯,似乎只有開始的前一段負數和最後的後一段負數可以改變。

然後若有所思的寫下一段代碼。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
 
const int N=1e5+1;
 
inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
 
int n,a[N];
int s=0;
 
int main(){
	n=read(); 
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=n;i++)
		if(a[i]<0) a[i]=-a[i];
		else break; //前一段
	for(int i=n;i>=1;i--)
		if(a[i]<0) a[i]=-a[i];
		else break; //後一段
	for(int i=1;i<=n;i++) s+=a[i];
	printf("%d\n",s);	
	return 0;
}

交上去,發現得了 689\frac{6}{89} 分。

發現 ai=0a_i = 0 有點問題。

算法三

ai=0a_i = 0?然後加了幾個等號。


#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
 
const int N=1e5+1;
 
inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
 
int n,a[N];
int s=0;
 
int main(){
	n=read(); 
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=n;i++)
		if(a[i]<=0) a[i]=-a[i];
		else break;
	for(int i=n;i>=1;i--)
		if(a[i]<=0) a[i]=-a[i];
		else break;
	for(int i=1;i<=n;i++) s+=a[i];
	printf("%d\n",s);	
	return 0;
}

然後得了 889\frac{8}{89} 分。

我卻,我答案是負數,它答案是正數

算法四

真正感到自己 腦抽了 挺堅強的。

其實呢,我們還是要重視它,畢竟是 CC 嗎。(其實也不難)

你想,比方說前一段是 AA,後一段是 CC,重疊是 BB,一共是 SS.(=0\emptyset = 0

(指前綴、後綴、重疊部分、總部分的和)

此時答案爲:

(A+B)+C-(A+B)+C

然而:

A+B+C=SA+B+C=S

(這是因爲,中間一段經過兩次之後沒變,所以還是加上)

所以答案變形爲:

(A+B)+C=(SC)+C=2×CS-(A+B)+C = -(S-C)+C = 2 \times C - S

顯然讓 CC 越大越好。

那答案不就擺在面前了?

Dev-c++:那你還調試那麼多次

因爲,CC 肯定是連續的一段並且你可以隨便的取,所以:

C = 原數列的最大子段和\texttt{C = 原數列的最大子段和}

哎呀,激動地寫了個程序。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
 
const int N=1e5+1;
 
inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
 
int n,a[N];
int s=0,f[N];
 
int main(){
	n=read(); 
	for(int i=1;i<=n;i++) a[i]=read(),s+=a[i];
	int ans=a[1]; f[1]=a[1];
	for(int i=2;i<=n;i++) f[i]=max(f[i-1]+a[i],a[i]),ans=max(ans,f[i]);
	printf("%d\n",ans*2-s);	
	return 0;
}

看上去沒啥問題,然後得了 0pt0pt.

原因: ans\texttt{ans} 的初值應該是:

max(a[1],0)

導致第一個樣例去世,然後全軍覆沒~

算法五

終於算是撥雲見霧了,結果在臨近 AC\texttt{AC} 的時候因爲初值掉坑。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
 
const int N=1e5+1;
 
inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
 
int n,a[N];
int s=0,f[N];
 
int main(){
	n=read(); 
	for(int i=1;i<=n;i++) a[i]=read(),s+=a[i];
	int ans=max(a[1],0); f[1]=a[1];
	for(int i=2;i<=n;i++) f[i]=max(f[i-1]+a[i],a[i]),ans=max(ans,f[i]);
	printf("%d\n",ans*2-s);	
	return 0;
}

終於 AC\text{AC} 了。時間複雜度:O(n)O(n).

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章