Codeforces Round #638 (Div. 2)

B - Phoenix and Beauty(思维)

题意: 给出一个长度为n的数组,要求构造一个数组相邻k个数的和相同
题解: 用set存放出现的数字,如果多于k就不能构造,否则就n*k构造即可,挺水的一道题然后突然被自己蠢到了。(掉分┭┮﹏┭┮)

#include <cstdio>
#include <iostream>
#include <cstring>
#include <set>
#include <algorithm>
using namespace std ;
typedef long long ll ; 
const int N = 1e5+10 ; 
int n,k,x ;
set<int> st ;  
int main(){
    int t; scanf("%d",&t) ;
    while(t--){
    	st.clear() ;
    	scanf("%d%d",&n,&k) ; 
    	for(int i=0 ; i<n ; ++i)	scanf("%d",&x) ,st.insert(x) ;
    	if(st.size() > k){
    		printf("-1\n") ; 
    		continue ; 
		}
		for(int i=1 ; st.size()<k ; ++i)	st.insert(i) ; 
		printf("%d\n",n*k) ; 
		for(int j=0 ; j<n ; ++j)
			for(set<int>::iterator it=st.begin() ; it!=st.end() ; ++it)		printf("%d ",*it) ; 
		printf("\n") ; 	
	}
    return 0 ; 
}

C - Phoenix and Distribution(思维)

题意: 给出一个长度字符串,要求分成k份,问分成的字符串中字典序最大的最小值是哪个字符串。
题解 先将字符串排序,要使得字典序变小前面尽量放小的,前k个数各取一个作为头,①、如果s[1]!=s[k]那就直接输出s[k],因为后面的字符和s[k]前面的组合一定比s[k]小,如果s[k]后面解字符肯定比单个s[k]大,②、如果s[k+1]!=s[n]说明,那么就直接输出s[k]和后面的,例如:n=5,k=2,排列后:aabbc,那先取各a为头,后面一个a解后面全部字符,就是 a abbc(最大为abbc) ,如果分一个到前面就是ab abc(最大为abc),或者ac abb(最大为ac),其中最大值的大小排列为(ac > abc > abbc),最后如果都不属于上面的情况就每隔k位输出即可。
这道题比较考察分析,(脑子越分析越乱,本来一开始倒是有点知道怎么做,越想越不会)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
typedef long long ll ; 
const int N = 1e5+10 ; 
char s[N] ; 
int n,k ; 
void solve(){
	if(s[1]!=s[k]){
		putchar(s[k]) ; 
		return ; 
	}
	if(s[k+1]!=s[n]){
		putchar(s[1]) ; 
		for(int i=k+1 ; i<=n ; ++i)		putchar(s[i]) ; 
		return ; 
	}
	for(int i=1 ; i<=n ; i+=k)		putchar(s[i]) ; 
}
int main(){
    int t; scanf("%d",&t) ;
    while(t--){
    	scanf("%d%d",&n,&k) ; 
    	scanf("%s",s+1) ;
    	sort(s+1,s+n+1) ; 
    	solve() ; 
    	putchar('\n') ; 
	}
    return 0 ; 
}

D - Phoenix and Science(数论)

题意: 每个细菌可以在白天的时候分裂,当一个细菌分裂成两个细菌时,子细菌的质量为母细菌的一半,晚上的时候,每个细菌的质量自增1,第一天会有一个质量为1的细菌。现要得到总质量为n的细菌,问最少几天能得到,并说明这几天内,每天分裂的细菌数。
题解: 若当天有x个细菌,那么晚上就会增加x的质量,如果白天分裂i个细菌,总细菌变成2*i+(x-i)=x+i,那么晚上就会增加x+i的质量。
要最少天数达到n,那么就尽量一直全部分裂,那么每一晚的增量就是2 , 4 ,8,16 ……,先找到最接近n的总和,比如1+2+4=7<10 , 然后多出来的3,就相当于其中有一天是增加3,那这个增加的3是在哪一天增加的呢,细菌数是直线上升的,所以3只能在2和4之间出现,所以增加的质量为:1 2 3 4 ,表示1 分裂成2个细菌,2个细菌分裂成3个细菌(即中间只有一个细菌分裂),3个细菌分裂成4个细菌(中间有一个细菌分裂),所以每天有几个细菌分裂就是这个增值的差值。
可以再用n=12来举例: 1+2+4=7<12 , 12-7=5 , 所以增量数组为:1 2 4 5 ,
1分裂成2(一个细菌分裂),2分裂成4(两个细菌分裂),4分裂成5(一个细菌分裂)。
感觉这道题还是蛮有意思的,直接从增量方面考虑(好题~~)

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std ;
typedef long long ll ; 
const int N = 1e5+10 ; 
vector<int> v ; 
int n,k ; 
int main(){
    int t; scanf("%d",&t) ;
    while(t--){
    	v.clear() ; 
    	int n ; scanf("%d",&n) ; 
    	int sum=0 ; 
		for(int i=1 ; sum+i<=n ; i<<=1){
    		sum += i ; 
    		v.push_back(i) ; 
		}
		if(sum<n)	v.push_back(n-sum) ; 
		sort(v.begin(),v.end()) ; 
		printf("%d\n",v.size()-1) ; 
		for(int i=1 ; i<v.size() ; ++i)		printf("%d ",v[i]-v[i-1]) ; 
		printf("\n") ; 
	}
    return 0 ; 
}

E - Phoenix and Berries (动态规划)

题意: 给出n颗树,还有n颗树上红果和蓝果的数量,每个篮放满需要k个果子,放在同一个篮子的果子必须是同种颜色或者是同一棵树上的果子,问最多能放满几个篮子。
题解: 用dp[i][j] 表示前i颗树上剩余j个红果子能放满的篮子数量,然后蓝果子的剩余数量为:总数量-篮子数量*k-红果子数量(bres=sum-dp[i][j]*k-j),处理当前树时可以看做:同色果子篮子数个+一个同树果子篮子,前面取整除即可,后面就可以枚举同一颗树上红果和蓝果数量,用s1表示放在同树果子篮子的红果数量,那么该篮子放蓝果为k-s1 , 除去这些加上本颗树的果子,红果子的数量为:本颗树红果数+上一颗树剩余数量-放在同树果篮子的数量(a[i]+j-s1), 蓝果子为:本颗树蓝果数量+蓝果剩余数-放在同树果子篮子数(b[i]+bres-(k-s1))
还有个很玄学的点就是,一开始全部数的类型都是long long,然后TLE了,后来只有sum、dp、mx是long long就能过了(迷惑.jpg),原来数据类型也是会影响运行时间的。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
typedef long long ll ; 
const int N = 510 ; 
ll dp[N][N]; 
int a[N] , b[N] ; 
int main(){
	int n,k ; scanf("%d%d",&n,&k) ; 
	for(int i=1 ; i<=n ; ++i)    scanf("%d%d",&a[i],&b[i]) ;
    memset(dp,-1,sizeof(dp)) ;
    dp[0][0]=0 ;
	ll sum=0 ;
	int anum,bnum;  
	for(int i=1 ; i<=n ; ++i){
		for(int j=0 ; j<k ; ++j){
			if(dp[i-1][j]==-1)	continue ; //前i-1颗树不存在剩余j的情况就跳过 
			ll bres=sum-dp[i-1][j]*k-j ;	//前i-1颗树装完之后剩余的蓝果数
			for(ll s1=1 ; s1<=a[i]&&s1<k ; ++s1){
				if(b[i]+s1>=k){
					anum=a[i]+j-s1 ; //除去放在不同色篮子的红果数
					bnum=b[i]+bres-(k-s1) ;
					dp[i][anum%k] = max(dp[i][anum%k],dp[i-1][j]+anum/k+bnum/k+1) ;  
				} 
			}
			anum=a[i]+j , bnum=b[i]+bres ; //同一颗树不同色不放在同一个篮子的果子数 
			dp[i][anum%k] = max(dp[i][anum%k],dp[i-1][j]+anum/k+bnum/k) ;  
		}
		sum += a[i]+b[i] ; 
	}
	ll mx=0 ;   
	for(int i=1 ; i<=n ; ++i){
		for(int j=0 ; j<=k ; ++j)
			mx = max(mx,dp[i][j]) ;
	}
	printf ("%lld\n",mx) ; 
	return 0 ; 
}

本次比赛总结:太菜了(掉分了┭┮﹏┭┮)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值