1400——1348B,698A,515C;Codeforces Round #745 (Div. 2)

今天是2021.9.23,下午刷了两道1400,晚上有场div2,打完又刷了一道。


1348.B. Phoenix and Beauty(构造)

大意:

构造一个序列,使序列中长度为k的子序列的元素之和始终为m。

思考:

让序列中长度为k的子序列元素之和都为m,那这个子序列一定是abcd abcd abcd…(abcd长度为k)

如果元素种类超过m,就构造不出。
因为所给序列长度不超过100,构造序列长度不超过10000,所以可以输出100组子序列。
构造长度为m,包含所有种类的子序列就行了。

Code:

const int N = 200010;
int T, n, m, a[N];
bool f[110];
int cnt;

int main(){
	Ios;
	cin>>T;
	while(T--)
	{
		cin>>n>>m;
		mem(f,0);
		cnt=0;
		
		for(int i=1;i<=n;i++)
		{
			int x;cin>>x;
			if(!f[x]) f[x]=1,a[++cnt]=x;
		}
		
		if(cnt>m){
			cout<<-1<<"\n";
			continue;
		}
		
		for(int i=cnt+1;i<=m;i++) a[i]=a[i-1];
		
		cout<<100*m<<"\n";
		for(int i=1;i<=100;i++){
			for(int j=1;j<=m;j++){
				cout<<a[j]<<" ";
			}
		}
		cout<<"\n";
	}
	
	return 0;
}

689.A. Vacations (dp)

大意:

每天最多有两种选择,但是不能连续两天都是同一选择。
问,最少休息多少天?

思考:

思路1:dfs
直接暴搜,超强剪枝:1.cnt超过ans退出;2.递归次数限制

思路2:dp
二维dp,将三种状态新开一维。
对于每个点,寻找当前状态的来源。

Code:

const int N = 200010;
int T, n, m, a[N];
int ans=1e9,cnt;
int step,flag;
int f[N][5];

void dfs(int u,int last)
{
	step++;
	if(step>=10000000){
		flag=1;return;
	}
	if(flag||cnt>=ans) return;
	
	if(u==n+1){
		ans=min(ans,cnt);
		return;
	}
	
	if(a[u]==0){
		cnt++;
		dfs(u+1,0);
		cnt--;
	}
	else if(a[u]==1)
	{
		if(last==1) cnt++,dfs(u+1,0),cnt--;
		else dfs(u+1,1);
	}
	else if(a[u]==2){
		if(last==2) cnt++,dfs(u+1,0),cnt--;
		else dfs(u+1,2);
	}
	else{
		if(last!=1) dfs(u+1,1);
		
		if(last!=2) dfs(u+1,2);
	}
}

void DP()
{
	for(int i=1;i<=n;i++) f[i][0]=f[i][1]=f[i][2]=-1e9;
	
	for(int i=1;i<=n;i++)
	{
		f[i][0]=max(f[i-1][0],max(f[i-1][1],f[i-1][2]));
		
		if(a[i]==1||a[i]==3) f[i][1]=max(f[i-1][0],f[i-1][2])+1;
		if(a[i]==2||a[i]==3) f[i][2]=max(f[i-1][0],f[i-1][1])+1;
	}
	ans=n-max(f[n][0],max(f[n][1],f[n][2]));
}

int main(){
	Ios;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	
//	dfs(1,0);
	DP();
	
	cout<<ans;
	
	return 0;
}

515.C. Drazil and Factorial (思维)

大意:

定于运算F(x),表示其所有位数阶乘的乘积。(x可能有前导0)
现给定x,要找到最大的a,使得F(a)=F(x),且a的每一位都不能为0或1。

思考:

要让a最大,就让x分解出的因子最多,就是分解出质因子,然后组成的a尽量长。

因为重组的a长度一定,要让a最大,就先将大的质因子输出。
因为F(a)=F(x),所以输出一个值x的时候,要把2~x的所有值的个数-1。

Code:

const int N = 200010;
int T, n, m, a[N];
int f[10][10]={{0},{1},{2},{3},{2,2},{5},{3,2},{7},{2,2,2},{3,3}};
int t[10]={0,1,1,1,4,1,2,1,3,2};
int cnt[10];

int main(){
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		char c;cin>>c;
		int x=c-'0';
		
		for(int j=2;j<=x;j++)
		{
			for(int k=0;k<t[j];k++)
			{
				cnt[f[j][k]]++;
			}
		}
	}
	
	for(int i=9;i>=2;i--)
	{
		while(cnt[i])
		{
			for(int j=i;j>=2;j--)
			{
				for(int k=0;k<t[j];k++){
					cnt[f[j][k]]--;
				}
			}
			cout<<i;
		}
	}
	
	return 0;
}


Codeforces Round #745 (Div. 2)

A. CQXYM Count Permutations (数论,思维)

大意:

给数n,问2n个数的全排列中,一共有多少序列满足: a i < a i + 1 ai<ai+1 ai<ai+1 的个数不少于 n。 n ≤ 1 e 5 n ≤1e5 n1e5,答案对 1 e 9 + 7 1e9+7 1e9+7取模。

思考:

这道题第一眼看上去是毫无头绪的,心想,艹,这是A题?
最后过掉才明白出题人的用意。

关键点在于:满足条件的位置个数不少于n,这个n很特殊,是突破点。
加上是2n个数的全排列,可以发现,2n个数的全排列中,一共有一半是满足条件的。

所以这道题就是要求:2n的全排列个数 / 2。

但是有个技巧的地方:
n很大,到1e5,如果边乘边取模,最后再除2,就和原来答案不一样了。
但是由于答案为 123*…*2n,最终再除2,所以就提前约分,将2约掉,从3开始往后乘,边乘边取模。这样就是正确的了。

Code:

const int N = 200010, mod=1e9+7;
int T, n, m, a[N];

int main(){
	Ios;
	cin>>T;
	while(T--)
	{
		cin>>n;
		if(n==1){
			cout<<1;
			cout<<"\n";
			continue;
		}
		else if(n==2){
			cout<<12;
			cout<<"\n";
			continue;
		}
		 
		ll ans=1;
		for(int i=3;i<=2*n;i++)
		{
			ans=ans*i%mod;
		}
		cout<<ans<<endl;
	}
	
	return 0;
}

B. Diameter of Graph (思维)

大意:

给n个点,m条边,问能否构成一个无向连通图,其两点间的最小距离中的最大值小于k-1。(没有重边和自环)

思考:

刚看到同样没有思路。

先分析m的范围限制:
因为是连通图,所以m要不小于n-1;
因为没有自环和重边,所以边数m最大不超过 C n 2 = n ∗ ( n − 1 ) / 2 C_n^2 = n*(n-1)/2 Cn2=n(n1)/2
所以 n-1 ≤ m ≤ n*(n-1)/2。

发现,当 m ∈ [n-1, n*(n-1)/2 ) 时,最小距离中的最大值都是2;
当 m = n*n(n-1)/2,也就是完全图,最小距离都为1。

所以,先判断m是否再范围中内,在判断k的大小就行了。

注意,特判点数n为1的情况。

Code:

const int N = 200010;
int T, n, m, a[N];

int main(){
	cin>>T;
	while(T--)
	{
		int k;
		cin>>n>>m>>k;
		
		if(n==1){
			if(k>=2&&m==0) cout<<"yes\n";
			else cout<<"no\n";
		}
		else if(m<n-1||m>(ll)n*(n-1)/2) cout<<"no\n";
		else if(k>=4) cout<<"yes\n";
		else if(k==3){
			if(m==(ll)n*(n-1)/2) cout<<"yes\n";
			else cout<<"no\n";
		}
		else cout<<"no\n";
	}
	
	return 0;
}

这场确实有点难了。
要不是队友搁旁边,准得掉大分。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值