Codeforces Round #604 (Div. 2) (題解)


A. Beautiful String (暴力)

題目鏈接

題目大意:

給定一個字符串,只有 \(?a\ b\ c\ ?\) ,問是否存在一種將所有的 \(?\) 替換成 \(a\ b\ c\) ,使得任意相鄰的字符不同的方法。

大致思路:

其實可以發現問號都可以通過枚舉使得其合法,若出現不合法必然除去問好已經不合法,暴力枚舉即可。

代碼:

點擊展開代碼
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
char s[N];
int T;
char c[3]={'a','b','c'};
int main()
{
	//freopen("H:\\c++1\\in.txt","r",stdin);
	//freopen("H:\\c++1\\out.txt","w",stdout);
	scanf("%d",&T);
	while(T--){
		scanf("%s",s+1);
		int len=strlen(s+1);
		for(int i=1;i<=len;i++){
			if(s[i]=='?'){
					for(int j=0;j<3;j++){
						if(c[j]!=s[i-1]&&c[j]!=s[i+1]){
							s[i]=c[j];break;
						}
					}
				
			}
		}
		int flag=0;
		for(int i=1;i<len&&flag==0;i++){
			if(s[i]==s[i+1])flag=1;
		}
		if(flag){
			puts("-1");
		}
		else printf("%s\n",s+1);
	}
	return 0;
}

B. Beautiful Numbers (思維)

題目鏈接

題目大意:

給一個排列,定義 \(m\) 為存在一段連續的 \(1 - m\) 的排列,如 \(\{4,5,1,3,2,6\}\) ,就存在 \({1,3,2}\) ,為 \(3\) 的排列,其就不存在 \(m=2\) 的排列。問對於每一個 \(m\) 判斷是否存在 \(1-m\) 的排列。

大致思路:

只要將每一個數字的位置記錄下來為 \(pos\) 數組,例如 \(\{4,5,1,3,2,6 \}\)\(pos\) 數組就是 \(\{3,5,4,1,2,6 \}\) 那么我們只要從前往后記錄最大值 \(max\) 和最小值 \(min\) ,然后 \(max-min+1==i\) 就是存在 \(1-m\) 的排列。

代碼:

點擊展開代碼
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
set<int>s; // 用set維護最大值最小值,其實不用那么麻煩
int T;
int a[N];
int pos[N];
int n;
int ans[N];
int main()
{
	//freopen("H:\\c++1\\in.txt","r",stdin);
	//freopen("H:\\c++1\\out.txt","w",stdout);
	scanf("%d",&T);
	while(T--){
		s.clear();
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			pos[a[i]]=i;
		}
		for(int i=1;i<=n;i++){
			s.insert(pos[i]);
			auto it=s.begin();
			int v1=*it;
			it=s.end();
			it--;
			int v2=*it;
			if(v2-v1+1==i)ans[i]=1;
			else ans[i]=0;
		}

		for(int i=1;i<=n;i++)printf("%d",ans[i]);
		puts("");
	}
	return 0;
}

C. Beautiful Regional Contest (貪心)

題目鏈接

題目大意:

\(n\) 個人的解題數,現在在發獎牌,金牌銀牌銅牌各 \(g,s,b\) 各,要求金牌解題數大於銀牌,\(...\) ,銅牌解題數大於無牌,且 \(g,s,b>0 \ \&\& \ g<s,g<b\) ,要求求出的合法的獎牌數,且最大。

大致思路:

一開始想多了,結果導致卡到了比賽結束。。。其實金牌的數量是確定,那么銀牌只要取得g+1,然后通過相同解題數看看銀牌最少要取多少個,看后計算銅牌最多能取多少個。判斷合法性即可。

代碼:

點擊展開代碼
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
int T;
int n;
int p[N];
int id[N],l[N],r[N],sum[N],cnt=0;
int qh(int L,int R){
	return sum[R]-sum[L-1];
}
int main()
{
	//freopen("H:\\c++1\\in.txt","r",stdin);
	//freopen("H:\\c++1\\out.txt","w",stdout);
	scanf("%d",&T);
	while(T--){
		cnt=0;
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d",&p[i]);
		}
		reverse(p+1,p+n+1);
		int temp=p[1];cnt++;l[cnt]=1;
		for(int i=1;i<=n;i++){
			if(p[i]==temp)id[i]=cnt;
			else{
				temp=p[i];
				r[cnt]=i-1;
				cnt++;
				l[cnt]=i;id[i]=cnt;
			}
		}
		r[cnt]=n;
		for(int i=1;i<=cnt;i++)sum[i]=r[i]-l[i]+1,sum[i]=sum[i-1]+sum[i];
		int mx=n/2;
		if(mx<5){
			puts("0 0 0");continue;
		}
		int flag=1;
		int pp=id[n];
		int g=sum[pp]-sum[pp-1];
		int pos=l[pp];
		int s=g+1;
		temp=pos-s;
		if(s+g>=n/2)flag=0;
		int pp1=id[temp];
		int pos1=l[pp1];
		s=pos-pos1;
		int sy=n-mx;
		int pp2=id[sy];
		int pos2=r[pp2]+1;
		pp2++;
		int b=pos1-pos2;
		if(b<=0||s<=0||b<=g||s<=g)flag=0;
		if(flag)printf("%d %d %d\n",g,s,b);
		else puts("0 0 0");
	}
	return 0;
}

D. Beautiful Sequence (枚舉)

題目鏈接

題目大意:

給四個數, \(a,b,c,d\) ,表示 \(a\)\(0\)\(b\)\(1\)\(c\)\(2\)\(d\)\(3\) ,要求將這些數排成一排,使得相鄰的數差值為1,輸出方案。

大致思路:

可以枚舉每一個數字做為開頭,然后就選擇相鄰的數字往后填,如果能填完,那么輸出方案即可。因為若存在答案,以4種數字開頭必然有一種是可以得到解的。

代碼:

點擊展開代碼
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int ans[N];
int flag=0;
vector<int>temp;
void dfs(int a,int b,int c,int d,int pos){
	if(a+b+c+d==0){
		flag=1;
		puts("YES");
		for(int v:temp)printf("%d ",v);
			puts("");exit(0);
	}
	if(pos==0&&b)temp.push_back(1),dfs(a,b-1,c,d,pos+1);
	if(pos==1){if(c)temp.push_back(2),dfs(a,b,c-1,d,pos+1);
			  else if(a)temp.push_back(0),dfs(a-1,b,c,d,pos-1);}
	if(pos==2){if(d)temp.push_back(3),dfs(a,b,c,d-1,pos+1);
			  else if(b)temp.push_back(1),dfs(a,b-1,c,d,pos-1);}
	if(pos==3&&c)temp.push_back(2),dfs(a,b,c-1,d,pos-1);

}
int a,b,c,d;

int main()
{
	//freopen("H:\\c++1\\in.txt","r",stdin);
	//freopen("H:\\c++1\\out.txt","w",stdout);
	scanf("%d%d%d%d",&a,&b,&c,&d);
	flag=0;
	if(flag==0&&a){
		temp.clear();
		temp.push_back(0);
		dfs(a-1,b,c,d,0);
	}
	if(flag==0&&b){
		temp.clear();
		temp.push_back(1);
		dfs(a,b-1,c,d,1);	
	}
	if(flag==0&&c){
		temp.clear();
		temp.push_back(2);
		dfs(a,b,c-1,d,2);
	}
	if(flag==0&&d){
		temp.clear();
		temp.push_back(3);
		dfs(a,b,c,d-1,3);
	}
	if(flag==0)puts("NO");
	return 0;
}

E. Beautiful Mirrors (概率DP)

題目鏈接

題目大意:

\(n\) 個鏡子,每一個鏡子有 \(p_i\) 的概率說美麗,現在我從第一個鏡子開始問,如果它說美麗,那么我就在下一天再問下一個鏡子,如果剛好到了第 \(n\) 個鏡子,那么我就會開心。否則我就下一天再從第一個鏡子開始問。問我開心需要的天數的期望值。

大致思路:

假設有 \(i\) 個鏡子,開心需要的天數為 \(F_i\) ,那么 \(F_i=P_i*(F_{i-1}+1)+(1-P_i)*(F_{i-1}+F_i+1)\)

就是在第 \(F_{i-1}\) 天必然是美麗,現在有 \(P_i\) 的概率是美麗,那么我就直接開心了,就是 \(F_{i-1}+1\) 天,還有剩下的概率,我需要從新開始那么就需要 \(F_{i-1}+F_i+1\) 天了。將式子化簡一下就是 \(F_i=(F_{i-1}+1)/P_i\) 循環一遍就行了。(就要概率要除100).

代碼:

點擊展開代碼
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e5+10;
const int mod=998244353;
ll ksm(ll a,ll b){
	ll res=1,t=a;
	while(b){
		if(b&1)res=(res*t)%mod;
		t=(t*t)%mod;
		b>>=1;
	}
	return res;
}
int n;
ll p[N],f[N];
int main()
{
	//freopen("H:\\c++1\\in.txt","r",stdin);
	//freopen("H:\\c++1\\out.txt","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%lld",&p[i]);
	f[0]=0;
	for(int i=1;i<=n;i++){
		f[i]=((100*(f[i-1]+1)%mod)*ksm(p[i],mod-2)%mod)%mod; //注意爆ll
	}
	printf("%lld\n",f[n]);
	return 0;
}

F. Beautiful Bracket Sequence (easy version) (DP)

題目鏈接

題目大意:

給一個字符串,字母只有括號和 \(?\) ,問對於所有的 \(?\) 填法,其括號嵌套數之和是多少。括號嵌套數是指一個括號序列最多的嵌套數,不要求合法,即可以刪除任意數量的括號后,保持相對位置不變的最大括號層數。例如對於:\((??)\) ,那么所有填法為 \((()),()(),())),((()\) ,這四種,答案就是 \(2+1+1+1=5\)

大致思路:

經過研究題解后,感覺大概懂了一些。用 \(dp[i][j]\) 表示區間 \([i,j]\) 的答案,那么我們考慮轉移方程,如果 \(s[i]\ !='('\) ,那么對於區間 \([i,j]\) ,對答案的貢獻必然是等於區間 \([i+1,j]\) 的,同理如果 \(s[j]\ !=')'\) ,那么對於區間 \([i,j]\) ,對答案的貢獻必然是等於區間 \([i,j-1]\) 的,當然如果都不等還是要考慮容斥的問題。那么這時考慮 \(s[i],s[j]\)\((),?),(?,??\) 的情況。那么對於 \([i,j]\) 來說必然會比 \([i+1,j-1]\) 多產生一點貢獻,因為必然能出現 \(()\) 的情形,如果 \([i+1,j-1]\) 的問號數為 \(k\) ,那么就多 \(2^k\) 的貢獻。那么轉移方程就可以寫出來。

\(dp[l][r]+=dp[l+1][r]\)\(s[l]\ !='('\)

\(dp[l][r]+=dp[l][r-1]\)\(s[r]\ !=')'\)

\(dp[l][r]-=dp[l+1][r-1]\) (容斥)

\(dp[l][r]+=dp[l+1][r-]+2^k\)\(s[l]\ !=')' \&\& s[r]\ !='('\)

代碼:

點擊展開代碼 ```c++ #include #define ll long long using namespace std; const int N=2e3+10; const int mod=998244353; ll dp[N][N]; int sum[N]; char s[N]; int js(int l,int r){ return sum[r]-sum[l-1]; } ll p[N]; int main() { //freopen("H:\\c++1\\in.txt","r",stdin); //freopen("H:\\c++1\\out.txt","w",stdout); p[0]=1; for(int i=1;i


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM