【codeforces】【比賽題解】#940 CF Round #466 (Div. 2)

人生的大起大落莫過如此,下一場我必定要回紫。html


【A】Points on the line數組

題意:lua

一個直線上有\(n\)個點,要求去掉最少的點,使得最遠兩點距離不超過\(d\)。spa

題解:code

暴力兩重for,更新答案。htm

#include<cstdio>
#include<algorithm>
using namespace std;
#define F(i,a,b) for(int i=(a);i<=(b);++i)
int n,q,ans=0;
int a[100001];
int main(){
	scanf("%d%d",&n,&q);
	F(i,1,n) scanf("%d",a+i);
	sort(a+1,a+n+1);
	F(i,1,n){
		int xx=a[i], kk=-1;
		F(j,i,n){
			if(a[j]-xx>q) break;
			kk=j;
		}
		ans=max(ans,kk-i+1);
	}
	printf("%d",n-ans);
	return 0;
}

【B】Our Tanya is Crying Out Loudblog

題意:隊列

一個數\(n\),每次你能夠花費\(A\)的代價把它除以\(k\)(若是\(k|n\)),或者花費\(B\)的代價把它減一。問把這個數變成1的最少代價。字符串

題解:get

暴力上,不能除減到能除爲止,能除看是除了花費少仍是不除花費少。

注意特判\(k=1\)。

#include<cstdio>
#define ll long long
int n,k,A,B;
ll ans;
int main(){
	scanf("%d%d%d%d",&n,&k,&A,&B);
	if(k==1) {printf("%lld",(ll)(n-1)*A);return 0;}
	while(n!=1){
		int x=n/k*k;
		if(x==0) {ans+=(ll)(n-1)*A; break;}
		if(n!=x) ans+=(ll)(n-x)*A, n=x;
		else{
			x=n/k;
			if((ll)(n-x)*A<=B) ans+=(ll)(n-x)*A;
			else ans+=B;
			n=x;
		}
	}
	printf("%lld",ans);
	return 0;
}

【C】Phone Numbers

題意:

限定字符集,求長度爲\(k\)的,字典序比給定長度爲\(n\)的字符串大的最小的字符串。

題解:

①\(k>n\)時,在原串後補上最小的字符。

②\(k<=n\)時,答案爲原串的前\(k\)位+1,即比原串\(k\)位前綴大的第一個字符串。

#include<cstdio>
#define F(i,a,b) for(int i=(a);i<=(b);++i)
#define F2(i,a,b) for(int i=(a);i<(b);++i)
int n,k,tot;
int px[150];
bool used[150];
char str[100010],use[30];
char ans[100010];
int main(){
	scanf("%d%d",&n,&k);
	scanf("%s",str);
	F2(i,0,n) used[str[i]]=1;
	F(i,1,140) if(used[i]) use[++tot]=i;
	F(i,1,tot) px[use[i]]=i; 
	if(k>n){
		printf("%s",str);
		F(i,n+1,k) printf("%c",use[1]);
		return 0;
	}
	F2(i,0,k) ans[i]=str[i]; ans[k]='\0';
	int x=k-1;
	while(px[ans[x]]==tot){
		ans[x]=use[1];
		--x;
	}
	ans[x]=use[px[ans[x]]+1];
	printf("%s",ans);
	return 0;
}

【D】Alena And The Heater

題意:

已知長度爲\(n\)的數組\(a\)和等長的01串\(b\),和經過\(a\)生成\(b\)的方法:

\(b_1=b_2=b_3=b_4=0\)

對於\(5\le i\le n\)

若是\(a_i,a_{i-1},a_{i-2},a_{i-3},a_{i-4}>r\) 而且\(b_{i-1}=b_{i-2}=b_{i-3}=b_{i-4}=1\),那麼\(b_i=0\)

若是\(a_i,a_{i-1},a_{i-2},a_{i-3},a_{i-4}<l\) 而且\(b_{i-1}=b_{i-2}=b_{i-3}=b_{i-4}=0\),那麼\(b_i=1\)

若是以上二者均不知足,那麼\(b_i=b_{i-1}\)。

試求出\(l,r\)的值。

題解:

能夠看到,對計算有貢獻的只有\(b\)中出現連續的4個相同數字的狀況。

經過這些狀況,咱們能夠肯定\(l,r\)的範圍,進而求出\(l,r\)的可能值。

由於題目保證有解,只需輸出最極端的值(\(l_{min},r_{max}\))便可。

#include<cstdio>
#include<algorithm>
using namespace std;
#define F(i,a,b) for(int i=(a);i<=(b);++i)
int n,ansll=-1000000000,ansrr=1000000000;
int a[100001];
char b[100009];
int main(){
	scanf("%d",&n);
	F(i,1,n) scanf("%d",a+i);
	scanf("%s",b+1);
	F(i,5,n){
		if(b[i-4]==b[i-3]&&b[i-3]==b[i-2]&&b[i-2]==b[i-1]){
			if(b[i-1]=='0'){
				int x=max(max(max(max(a[i],a[i-1]),a[i-2]),a[i-3]),a[i-4]);
				if(b[i]=='1'){
					//l > max(a 1~5)
					ansll=max(ansll,x+1);
				}
			}
			else{
				int x=min(min(min(min(a[i],a[i-1]),a[i-2]),a[i-3]),a[i-4]);
				if(b[i]=='0'){
					//r < min(a 1~5)
					ansrr=min(ansrr,x-1);
				}
			}
		}
	}
	printf("%d %d",ansll,ansrr);
	return 0;
}

【E】Cashback

題意:

給定一個長度爲\(n\)的數組\(a\)和一個常數\(c\)。你能夠把\(a\)數組分割成連續的若干段,每一段的代價分別計算:

對於長度爲\(len\)的一段,其代價爲其元素總和,減去最小的\(\left \lfloor \frac{len}{c} \right \rfloor\)個元素。

求最小總代價。

題解:

既然要讓代價最小,咱們轉化爲求最大的價值,再用全部的元素和減去這個價值便可。

那就變成了長度爲\(len\)的一段,其價值爲最小的\(\left \lfloor \frac{len}{c} \right \rfloor\)個元素的和。

首先咱們注意到一個結論:有貢獻價值的分段,其長度正好爲\(c\)時,沒有其餘方法比它更優。

證實請自行腦補……由於我也沒想清楚,當時考場上瞎猜的結論,有興趣的讀者不妨看看http://www.cnblogs.com/kkkkahlua/p/8468896.html

那麼,咱們經過單調隊列處理出每一個長爲\(c\)的區間的最小值,記爲\(b\)數組。

那麼有DP方程\(f[i]=(max_{j=1}^{i-c}f[i])+b[i-c+1]\),表示前\(i\)個數,最後一個區間必須選取的最大價值,答案爲\(Sum-max(f[i])\)。

#include<cstdio>
#include<algorithm>
using namespace std;
#define F(i,a,b) for(int i=(a);i<=(b);++i)
#define ll long long
int n,c;
int a[100009],b[100009];
int que[100009],l=1,r=0;
ll sum,f[100009],g[100009];
int main(){
	scanf("%d%d",&n,&c);
	F(i,1,n) scanf("%d",a+i);
	F(i,1,n) sum+=a[i];
	if(c>n) {printf("%lld",sum); return 0;}
	F(i,1,c){
		while(l<=r&&a[que[r]]>=a[i]) --r;
		que[++r]=i;
	} b[1]=a[que[l]];
	F(i,c+1,n){
		if(que[l]<=i-c) ++l;
		while(l<=r&&a[que[r]]>=a[i]) --r;
		que[++r]=i;
		b[i-c+1]=a[que[l]];
	}
	F(i,1,n-c+1){
		if(i<=c) f[i]=b[i];
		else{
			f[i]=b[i]+g[i-c];
		}
		g[i]=max(g[i-1],f[i]);
	}
	printf("%lld",sum-g[n-c+1]);
	return 0;
}
相關文章
相關標籤/搜索