1. 程式人生 > 其它 >(Training 16)Codeforces Round #687

(Training 16)Codeforces Round #687

技術標籤:codeforces訓練資料結構演算法動態規劃字串

A. Prison Break

題意:給出地圖大小n*m 和點 (x,y)問地圖上距離該點最遠的點是多少
思路:4個角落必然最遠 取最大即可

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
	int T;
	cin>>T;
	while(T--){
		int n,m,x,y;
		cin>>
n>>m>>x>>y; cout<<max({x-1+y-1,m-x+n-y,n-x+y-1,x-1+m-y})<<endl; } }

B. Repainting Street

題意:長度為n的圖 大小為K的刷子 問最少多少次能將圖刷為一個顏色
思路:首先一共10種 地圖長度是1e5
那麼我們直接向後列舉 統計上次顏色出現的位置 和 上次 刷該顏色時顏色最後保留的位置 求出需要刷多少次即可 累加求出結果
最後再以n為結尾點統計一次答案即可

#include<iostream>
#include<cstring>
#include<vector> #include<algorithm> using namespace std; const int N=1e3+10; int cnt[N],pre[N],pro[N]; int a[100010]; int main(){ int T; cin>>T; while(T--){ int n,k; scanf("%d%d",&n,&k); memset(cnt,0,sizeof cnt); memset(pre,0,sizeof pre); memset(pro,0,sizeof
pro); for(int i=1;i<=n;i++){ int x; scanf("%d",&x); a[i]=x; if(pre[x]<i-1&&pro[x]<i-1){//上次塗色位置大於K int t=(i-1-max(pre[x],pro[x])+k-1)/k;//求出需要刷多少次 cnt[x]+=t; pro[x]=max(pro[x],pre[x])+k*t; } pre[x]=i; } int ans=0x3f3f3f3f; for(int i=1;i<=100;i++){ if(pre[i]<n&&pro[i]<n) cnt[i]+=(n-max(pre[i],pro[i])+k-1)/k; ans=min(ans,cnt[i]); } cout<<ans<<endl; } }

C. Bouncing Ball

題意:刪除第一個點的時間為y 將一個點變為1的時間為x
求出使得平臺的第p個點和分別 第p+k p+2k…個點都能滿足這幾個位置為1
思路:因為只能刪除前面 所以我們考慮從後往前統計
h[i]=h[i+k]+1sum[i]=sum[i+k]+(str[i]=='1')
即位置i為p的話 需要多少個1和位置i有多少個1
這時候我們就知道了 再從前往後推一次 取min

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N=2e5+10;
char str[N];
int sum[N],h[N];
int main(){
	int T;
	cin>>T;
	while(T--){
		int n,k,p;
		memset(sum,0,sizeof sum);
		memset(h,0,sizeof h);
		scanf("%d%d%d",&n,&p,&k);
		scanf("%s",str+1);
		int x,y;
		scanf("%d%d",&x,&y);
		//cout<<x<<" "<<y<<endl;
		int ans=1e9+10;
		for(int i=n;i>=1;i--){
			h[i]+=h[i+k]+1;
			sum[i]+=sum[i+k]+(str[i]=='1');
		}
		for(int i=1;i<=n;i++){
			if(i>=p){
				ans=min(ans,y*(i-p)+(h[i]-sum[i])*x);
				//cout<<y*(i-p)<<" "<<i-p<<" "<<(h[i]-sum[i])<<" "<<y<<endl;
			}
		}
		cout<<ans<<endl;
	} 
}

D. XOR-gun

題意:給出一個升序(ai<=aj,i<j)的陣列
可以選擇2個數將他進行異或運算後加入陣列中
可以不斷進行該操作 最少多少次操作能使得陣列不滿足升序
在這裡插入圖片描述

思路:這個並不是個數據結構(字典樹)
而需要觀察 由於是異或操作 我們考慮二進位制
因為每個數均小於1e9
轉換為2進位制後 最高的數有30位
如果相鄰2個數進行異或操作後 他小於左邊的數 那麼他們這2個數必定高位相同這樣異或操作後高位被消去 那麼當如果相鄰有3個數的最高位相同 那麼必然運算元為1 而當超過60個數以後 就必定有相鄰有3個數的最高位相同 而這時候 我們只需要考慮小於60的情況 那麼我們只要進行列舉即可 不管是3次方 4次方也好。。。都能過

#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int a[N];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		a[i]^=a[i-1];
	}
	if(n>=60){
		return puts("1"),0;
	}
	int ans=n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++)
			for(int k=i+1;k<=n;k++){
				if((a[i]^a[j-1])>(a[i]^a[k]))//(i+1到K k-i-2次)(i-j+1次) 
				ans=min(ans,k-j-1);
			}
	}
	if(ans!=n)
	cout<<ans;
	else puts("-1");
	return 0;
}