1. 程式人生 > >CF Round #522 (Div. 2)

CF Round #522 (Div. 2)

ACM題集:https://blog.csdn.net/weixin_39778570/article/details/83187443
題目連結:http://codeforces.com/contest/1079
官方題解:http://codeforces.com/blog/entry/63324

A題

題意:吃一種食物需要完整的一套餐具,每套餐具是是一樣的,由不同的餐具組成,如刀子,叉子,筷子(由不同的數字表示,如1,2,3)。用餐過程會被偷掉一些餐具。現在知道最後剩下n個餐具,分別為a[1],a[2],a[3]…a[n],和k個客人,問最少被偷掉幾個餐具
解法:最主要的點是算出食物的數目(fish),跟據餐具的套數算出最少的fish
fish的最少為 餐具套數/人數 (向上取整)
a

n s = s u m f i s h
k n ans = sum*fish*k-n (sum為一套餐具最少有幾種餐具)

#include<bits/stdc++.h> 
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std; int n,k,a[200]; int main(){ cin>>n>>k; int x; fo(i,1,n){ scanf("%d",&x); a[x]++; } int mx= -1,sum=0; fo(i,1,100){ if(a[i]) mx = max(mx,a[i]),sum++; } if(mx%k==0)mx/=k; else mx = mx/k +1; int ans = sum*mx*k - n; cout<<ans; return 0; }

B題

題意:問一個字串最少能分成幾行,每列最多20個字元。形成一個矩陣,不為矩陣由*代替,兩行差不能超過2個星
解法:算出最少有多少行,跟據行算出列,算出有多少個星星,輸出,每行最多一個星星

#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;

char s[106];
int main(){
	scanf("%s",s+1);
	int len = strlen(s+1);
	int row = len%20==0? len/20:len/20+1;
	int col = len%row==0? len/row:len/row+1;
	int xin = row * col - len;
	int t1 = 0, t2=1;
	cout<<row<<" "<<col<<endl;
	fo(i,1,row){
		int j = 1;
		if(t1++<xin)printf("*"),j++;
		for(j; j<=col; j++){
			printf("%c",s[t2++]);
		}
		printf("\n");
	} 
}

C題

題意:給定一個數列a,求數列b, 1 &lt; = b [ i ] &lt; = 5 1&lt;=b[i]&lt;=5
i f   a [ i ] &lt; a [ i + 1 ]   t h e n   b [ i ] &lt; b [ i + 1 ] if \ a[i]&lt;a[i+1] \ then \ b[i]&lt;b[i+1]
i f   a [ i ] &gt; a [ i + 1 ]   t h e n   b [ i ] &gt; b [ i + 1 ] if \ a[i]&gt;a[i+1] \ then \ b[i]&gt;b[i+1]
i f   a [ i ] = a [ i + 1 ]   t h e n   b [ i ] b [ i + 1 ] if \ a[i]=a[i+1] \ then \ b[i]≠b[i+1]
解法:
記憶化搜尋,O(5n)
d p [ s t e p ] [ i ] = x dp[step][i]=x 表示第 s t e p 1 step-1 步的值為 x x , s t e p step 步的值為$i $
d f s ( s t e p , x ) dfs(step,x) 表示第 s t e p 1 step-1 步的值為x是否合法,合法返回 s t e p 1 step-1 的值

#include<bits/stdc++.h>
#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;

int n,dp[100005][6],a[100005]; 
// dp[step][i]=x 表示第step-1步的值為x,step步的值為i 
// dfs(step,x) 表示第step-1步的值為x是否合法,合法返回step-1的值 
bool dfs(int step, int x){// step當前,x屬於step-1 
	if(step>n) return dp[step][0]=x;
	if(dp[step][x]!=-1)return dp[step][x];
	if(a[step]>a[step-1]){
		fo(i,x+1,5){
			if(dfs(step+1,i))return dp[step][i]=x; // 搜對了才賦值,相當於回溯,但顯然比回溯快 
		}										   // 因為回溯會破壞掉之前已經搜尋過的錯誤解空間,導致重判 
	}else if(a[step]<a[step-1]){
		fo(i,1,x-1){
			if(dfs(step+1,i))return dp[step][i]=x;
		}
	}else{
		fo(i,1,5)if(i!=x){		
			if(dfs(step+1,i))return dp[step][i]=x;
		}
	}
	return dp[step][x]=0; // 上個值x搞錯了,往後都不合法 
}
int b[100005];
int main(){
	cin>>n;
	fo(i,1,n)scanf("%d",&a[i]);
	memset(dp,-1,sizeof(dp));
	dfs(1,0); // 出口總返回0, 第0號元素的值 
	if(dp[n+1][0]!=-1){
		int t=n;
		for(int x=dp[n+1][0],i=n; i>=1; x=dp[i][x],i--){
			b[t--]=x; // 往回賦值 
		}
		fo(i,1,n)printf("%d%c",b[i],i==n?'\n':' ');
		return 0;
	}
	puts("-1");
	return 0;
}

D題

題意:給一個網格上的兩個點a,b和一條直線 Ax+By+C=0。點a只能沿著網格或這直線走到b。問最小行走距離。
解法:列舉a不走直線到b。
a沿x軸走到直線到達點a1,a沿y軸走到直線到達點2
同理得b1,b2.
列舉 a --> a(1or2) --> b(1or2) --> b 的距離
取5種情況的最小值

#include<bits/stdc++.h> 
#define ll long long 
#define fo(i,j,n) for(register int i=j; i<=n; i++)
using namespace std;
double a,b,c,x1,y1,x2,y2,xa[6],ya[6],xb[6],yb[6];
double dist(double x1,double y1,double x2, double y2){
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int main(){
	cin>>a>>b>>c;
	cin>>x1>>y1>>x2>>y2;
	xa[1]=x1,ya[1]=-(a*xa[1]+c)/b; // a上下 
	ya[2]=y1,xa[2]=-(b*ya[2]+c)/a; // a左右
	xb[1]=x2,yb[1]=-(a*xb[1]+c)/b; // b上下 
	yb[2]=y2,xb[2]=-(b*yb[2]+c)/a; // b上下 
	double ans = fabs(x1-x2)+fabs(y1-y2);
	fo(i,1,2)fo(j,1,2){
		ans = min(ans, fabs(xa[i]-x1)+fabs(ya[i]-y1)+fabs(xb[j]-x2)+fabs(yb[j]-y2)+dist(xa[i],ya[i],xb[j],yb[j]));
	}
	printf("%.10f\n",ans);
	return 0;
}

E題

題意:把一種質量看做一種商品。給定一些商品的重量即數列a[1],[2],a[3]…a[n],但是同學1無法區分重量和商品,但是他可以問同學2:k個商品的重量和sum有哪些。同學2會指出哪k個商品和為sum(如果存在的話)。問同學1最多能區分多少個商品,也就是說具體知道哪些商品的重量。

解法:由於同學1太傻了,所以同學2一但指出k個商品但是商品中有不同種類的,那麼同學1還是無法得知哪個商品具體是哪個。
那麼同學1只能詢問同一種商品,k個了。
f [ i ] [ j ] f[i][j] 表示i個商品組成質量為j的組合數。
這裡的組合數是這樣的
如數 2 2 2 2 2 2 2 2
被算為 2 4 6 8 共4種組合 ,而不是01揹包那樣, 4 可以由不同的2組成,然後進行多次計算
f [ 1 ] [ 2 ] = 1 , f [ 2 ] [ 4 ] = 1 , f [ 3 ] [ 6 ] = 1 , f [ 4 ] [ 8 ] = 1 f[1][2] = 1, f[2][4] = 1, f[3][6] = 1, f[4][8] = 1