[題解](更新中)Refact.ai Match 1 (Codeforces Round 985)

Sinktank發表於2024-11-11

A - Set

顯然答案是\(\max(\lfloor\frac{r}{k}\rfloor-l+1,0)\)

點選檢視程式碼
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,l,r,k;
signed main(){
	cin>>t;
	while(t--){
		cin>>l>>r>>k;
		cout<<max(0ll,r/k-l+1)<<"\n";
	}
	return 0;
}

B - Replacement

我們發現只要\(0\)\(1\)各存在至少\(1\)個,操作就能進行下去。所以\(r_i=1\)的操作可以看做刪掉一個\(0\)\(r_i=0\)的操作則可以看做刪掉一個\(1\)

這樣模擬就可以了,每次操作前如果剩餘\(0,1\)的個數存在\(0\)則答案是NO

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;
int t,n;
string s,r;
int main(){
	cin>>t;
	while(t--){
		cin>>n>>s>>r;
		int cnt0=0,cnt1=0;
		bool f=1;
		for(char i:s) (i=='0'?cnt0:cnt1)++;
		for(char i:r){
			if(!cnt0||!cnt1){
				f=0;
				break;
			}
			(i=='0'?cnt1:cnt0)--;
		}
		cout<<(f?"YES\n":"NO\n");
	}
	return 0;
}

另一種做法很簡單,如果\(s[1,n]\)\(1\)的個數減去\(r[1,n-2]\)\(0\)的個數為\(1\),答案就是YES,否則NO。原理差不多,目的是讓執行最後一次操作前,序列中恰好有一個\(0\)和一個\(1\)

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;
int t,n;
string s,r;
int main(){
	cin>>t;
	while(t--){
		cin>>n>>s>>r;
		r.pop_back();
		int cnts=0,cntr=0;
		for(int i:s) cnts+=(i=='1');
		for(int i:r) cntr+=(i=='0');
		if(cnts-cntr==1) cout<<"YES\n";
		else cout<<"NO\n";
	}
	return 0;
}

C - New Rating

二分解法

考慮二分答案\(x\),轉為判斷“是否能讓最終得分\(\ge x\)”。

\(f[i]\)表示參加第\(i\)場比賽之後的得分;\(g[i]\)表示\(i\)這場比賽前可能的最小得分,使得最終得分\(\ge x\)\(f\)可以透過模擬求出,\(g\)可以用下面的方法求得:

\[g[i]=\begin{cases} x&i=n\\ g[i+1]-1&i\le n,a[i]\ge g[i+1]\\ g[i+1]+1&i\le n,a[i]<g[i+1] \end{cases}\]

只要存在區間\(l\le r\),使得\(f[l-1]\ge g[r+1]\),則說明我們可以讓最終得分\(\ge x\)

時間複雜度\(O(n\log n)\)

點選檢視程式碼
#include<bits/stdc++.h>
#define N 300010
using namespace std;
int t,n,a[N],f[N];
bool check(int x){
	int g=x;
	for(int i=n;i>=1;i--){
		if(f[i-1]>=g) return 1;
		if(a[i]>=g) g--;
		else g++;
	}
	return 0;
}
int main(){
	cin>>t;
	while(t--){
		cin>>n;
		int cur=0;
		for(int i=1;i<=n;i++){
			cin>>a[i];
			if(a[i]>cur) cur++;
			else if(a[i]<cur) cur--;
			f[i]=max(f[i-1],cur);
		}
		int l=0,r=n;
		while(l<r){
			int mid=(l+r+1)>>1;
			if(check(mid)) l=mid;
			else r=mid-1;
		}
		cout<<l<<"\n";
	}
}

DP解法

\(f[i][j\in[0,2]]\)來表示考慮前\(i\)個比賽,第\(i\)場的狀態是\(j\)的答案。其中\(j=0,1,2\)分別表示在跳過的比賽之前、屬於跳過的比賽、在跳過的比賽之後。則

\[f[i][j]=\begin{cases} g(f[i-1][0],a[i])&j=0\\ \max(f[i-1][0],f[i-1][1])&j=1\\ \max(g(f[i-1][1],a[i]),g(f[i-1],a[i]))&j=2 \end{cases}\]

轉移可以滾掉第\(1\)維。最終答案就是\(\max(f[n][1],f[n][2])\)

時間複雜度\(O(n)\)

點選檢視程式碼
#include<bits/stdc++.h>
#define int long long
#define N 300010
using namespace std;
int t,n,a[N],f[3];
int g(int a,int b){return a+(b>a)-(b<a);}
signed main(){
	cin>>t;
	while(t--){
		cin>>n;
		for(int i=1;i<=n;i++) cin>>a[i];
		f[0]=0,f[1]=f[2]=INT_MIN;
		for(int i=1;i<=n;i++){
			f[2]=max(g(f[1],a[i]),g(f[2],a[i]));
			f[1]=max(f[1],f[0]);
			f[0]=g(f[0],a[i]);
		}
		cout<<max(f[1],f[2])<<"\n";
	}
	return 0;
}

D - Cool Graph

相關文章