Codeforces Global Round 10 題解 (DEF)


D. Omkar and Bed Wars

大意:n個人站成一個圈,i的右邊是i+1,n的右邊是1。他們初始有一個朝向(朝左/右)。每次操作可以讓一個人轉向(左變右或相反)。要求不出現連續三個朝左或連續三個朝右的人,求最小操作數

拿到題容易想到貪心。當時我仔細思考了億年,覺得寫起來麻煩得一批,於是投入dp的懷抱

\(dp[i][i_1][i_2][k_1][k_2]\) 為前 \(i\) 個人的代價最小值,其中第 \(1\) 個人朝向 \(i_1\),第 \(2\) 個人朝向 \(i_2\),第 \(i-1\) 個人朝向 \(k_1\),第 \(i\) 個人朝向 \(k_2\)相信大家能一眼看出狀態轉移方程我就懶得講了

復雜度 \(O(16n)\)

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
#define mst(a,x) memset(a,x,sizeof(a))
#define fi first
#define se second
//#define endl "\n"
mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
const int N=200010; typedef long long ll; const int inf=~0u>>2; const ll INF=~0ull>>2; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;} typedef double lf; const lf pi=acos(-1.0); lf readf(){lf x; if(scanf("%lf",&x)==-1)exit(0); return x;} typedef pair<ll,ll> pii; template<typename T> void operator<<(vector<T> &a,T b){a.push_back(b);}
const ll mod=(1?1000000007:998244353); ll mul(ll a,ll b,ll m=mod){return a*b%m;} ll qpow(ll a,ll b,ll m=mod){ll ans=1; for(;b;a=mul(a,a,m),b>>=1)if(b&1)ans=mul(ans,a,m); return ans;}
#define int ll
int a[N]; char s[N];
int dp[N][2][2][2][2];
void Solve(){
	int n=read();
	scanf("%s",s);
	repeat(i,0,n)a[i]=s[i]=='R';
	repeat(i,0,n)
	repeat(i1,0,2)
	repeat(i2,0,2)
	repeat(k1,0,2)
	repeat(k2,0,2)
		dp[i][i1][i2][k1][k2]=inf;
	repeat(i1,0,2)
	repeat(i2,0,2){
		dp[1][i1][i2][i1][i2]=(a[0]!=i1)+(a[1]!=i2);
	}
	repeat(i,2,n)
	repeat(i1,0,2)
	repeat(i2,0,2)
	repeat(k1,0,2)
	repeat(k2,0,2)
	repeat(k3,0,2)
	if(!(k1==k2 && k2==k3)){
		dp[i][i1][i2][k2][k3]=min(dp[i][i1][i2][k2][k3],
			dp[i-1][i1][i2][k1][k2]+(a[i]!=k3));
	}
	ll ans=inf;
	repeat(i1,0,2)
	repeat(i2,0,2)
	repeat(k1,0,2)
	repeat(k2,0,2){
		if(!(k1==k2 && k1==i1))
		if(!(k2==i1 && k2==i2))
			ans=min(ans,dp[n-1][i1][i2][k1][k2]);
	}
	cout<<ans<<endl;
}
signed main(){
	//freopen("data.txt","r",stdin);
	int T=1; T=read();
	while(T--)Solve();
	return 0;
}

E. Omkar and Duck

大意:(交互題)先告訴你 \(n\),讓你給出 \(n\times n\) 的矩陣,然后 \(q\) 組詢問,每次會給出 矩陣中 從右上到左下的某一最短路徑上 的數字之和,輸出路徑長什么樣

這題我寫了兩遍題解了,全都不滿意刪掉了,氣死,直接上代碼

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
#define mst(a,x) memset(a,x,sizeof(a))
#define fi first
#define se second
//#define endl "\n"
mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
const int N=30; typedef long long ll; const ll INF=~0ull>>2; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
#define int ll
int n,a[N][N]; //a即要輸出的那個矩陣
pair<ll,ll> g[N][N]; //g[i][j]表示如果走到(i,j)這個位置,那么走過的數字之和一定在區間[g[i][j].first,g[i][j].second]內
//g[][]要求在所有左下-右上的斜線上的所有點,其值域兩兩不相同,並且單增
vector<pair<ll,ll>> ans;
void Solve(){
	int n=read();
	a[0][0]=0;
	g[0][0]={0,0};
	repeat(sum,1,n*2-1){ //遍歷斜線
		int pre=-1;
		repeat(j,0,n)
		repeat(i,0,n)
		if(i+j==sum){ //處理斜線上的點
			int mn=INF,mx=-INF;
			if(i)mn=min(mn,g[i-1][j].fi),mx=max(mx,g[i-1][j].se);
			if(j)mn=min(mn,g[i][j-1].fi),mx=max(mx,g[i][j-1].se); //此時,[mn,mx]為前兩個點的值域的並集
			g[i][j]={pre+1,pre+1+mx-mn}; //pre+1是為了與剛剛處理的點值域剛好不相交
			a[i][j]=g[i][j].fi-mn;
			pre=pre+1+mx-mn; //值域最大值
		}
	}
	repeat(i,0,n){
		repeat(j,0,n)
			printf("%lld ",a[i][j]);
		puts("");
	}
	fflush(stdout);
	int q=read();
	while(q--){
		ans.clear();
		int s=read(); int x=n-1,y=n-1; ans.push_back({x,y});
		while(x || y){ //模擬一遍,把路徑模擬出來
			if(!x)y--;
			else if(!y)x--;
			else{
				s-=a[x][y];
				if(g[x-1][y].fi<=s && g[x-1][y].se>=s)
					x--;
				else y--;
			}
			ans.push_back({x,y});
		}
		repeat_back(i,0,ans.size())
			printf("%lld %lld\n",ans[i].fi+1,ans[i].se+1);
		fflush(stdout);
	}
}
signed main(){
	//freopen("data.txt","r",stdin);
	int T=1; //T=read();
	while(T--)Solve();
	return 0;
}

F. Omkar and Landslide

發生了一個恐怖的事情

我2020年1月的時候隨手出了一道題,當時是打算給noip提高組出題,並且鍛煉一下出題能力。結果剛好和這題撞了,甚至輸入輸出格式也是一樣的,唯一區別是我的n是2e5,這題是1e6,還有高度我是1e9,這題是1e12(有區別嗎?)

(當時覺得,從算法角度看,應該是不到noip提高組的難度的,也就寫起來有點繁瑣)

蕪湖,找來以前的代碼直接嘿嘿嘿,老鐵們我做得對嗎

大意:給出n個嚴格單調遞增的數列,不斷重復如下操作直到無法操作:選擇一個i滿足 a[i+1]-a[i]>=2,然后 a[i+1]--; a[i]++;

憋說了,大模擬,莽就完了。先a[i]-=i,然后模擬一個棧,每個元素表示一段相同的a[i],然后就是各種討論,好煩啊,還能咋做捏

我回來了。不是吧阿sir,原來這題是我那題的簡單版本,因為我的題目的初始序列是單調不減的,這題是單調遞增的,那最終狀態只與sum(a[i])有關。那為什么放F題位置啊喂!

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
#define mst(a,x) memset(a,x,sizeof(a))
#define fi first
#define se second
//#define endl "\n"
mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
const int N=1000010; typedef long long ll; const int inf=~0u>>2; const ll INF=~0ull>>2; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;} typedef double lf; const lf pi=acos(-1.0); lf readf(){lf x; if(scanf("%lf",&x)==-1)exit(0); return x;} typedef pair<ll,ll> pii; template<typename T> void operator<<(vector<T> &a,T b){a.push_back(b);}
#define int ll
int n,a[N];
vector<pii> s;
void Solve(){
	n=read();
	repeat(i,1,n+1)
		a[i]=read(),a[i]-=i;
	s.push_back({a[1],1});
	repeat(i,2,n+1){
		if(a[i]<s.back().first){
			s.push_back({a[i],i});
			continue;
		}
		if(a[i]==s.back().first)continue;
		while(s.size()>1 && a[i]-s.back().first>i-s.back().second){
			a[i]-=i-s.back().second;
			s.pop_back();
		}
		if(s.size()==1){
			int t=(a[i]-s.back().first)/(i-1+1);
			a[i]-=t*(i-1);
			s.back().first+=t;
		}
		if(a[i]==s.back().first)continue;
		int d=a[i]-s.back().first;
		pii t=s.back();
		if(s.size()==1)s.back().first++;
		else s.pop_back();
		s.push_back({t.first,t.second+d});
	}
	s.push_back({0,INF});
	int p=0;
	repeat(i,1,n+1){
		if(s[p+1].second==i)p++;
		printf("%lld ",s[p].first+i);
	}
	puts("");
}
signed main(){
	//freopen("data.txt","r",stdin);
	int T=1; //T=read();
	while(T--)Solve();
	return 0;
}


免責聲明!

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



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