Codeforces Round 1043 (Div. 3)

虽然说只写了三道题,但是这次的题目和以往的风格稍微有点不一样。其实题不算难只是之前可能这种风格练得少思维一下转换不过来浪费了一点时间。Div3打的真"难受",Div2写两题感觉写不了也不想啥了,Div3开到第4题思路想通了调了半天没调对打完真不甘心,都不想睡了。这次比赛的思维也非常值得学习,确实是之前练的不多的!

本场链接:Dashboard - Codeforces Round 1043 (Div. 3) - Codeforces

A. Homework

思路

  • 按照题意模拟就行

代码

cpp 复制代码
// Problem: A. Homework
// Contest: Codeforces - Codeforces Round 1043 (Div. 3)
// URL: https://codeforces.com/contest/2132/problem/0
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

void solve()
{
	string s1,s2,s3;
	cin >> n;
	cin >> s;
	cin >> m;
	cin >> s1;
	cin >> s2;
	for(int i=0; i<s2.size(); i++)
	{
		if(s2[i]=='V') s=s1[i]+s;
		else s=s+s1[i];
	}
	cout << s << endl;
}

B. The Secret Number

思路

我们可以设原数为n,那么此时的数就是n0000···+n,可以归纳为n*(1+10^i),n=x/(1+10^i)那么我们就从最大可能的数向小的遍历100000001->1000001->···->11,如果可以整除那么这个商就是符合的

代码

cpp 复制代码
// Problem: The Secret Number
// Contest: Virtual Judge - CodeForces
// URL: https://vjudge.net/problem/CodeForces-2132B#author=GPT_zh
// Memory Limit: 1024 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

void solve()
{
	cin >> n;
	vector<int> v;
	int k=1;
	for(int i=1; i<=18; i++)
	{
		k*=10;
		int num=1+k;
		if(n%num==0) v.push_back(n/num);
	}
	cout << v.size() << endl;
	sort(v.begin(),v.end());
	for(auto i:v) cout << i << ' ';
	if(v.size()!=0)
	cout << endl;
}

C1. The Cunning Seller (easy version)

思路

本质就是一个三进制拆分,可以参考二进制拆分。老板要刚好买n个西瓜的情况下还要尽量多的获取利润,我们可以把利润公式归纳为(x+9)*3^(x-1),通过公式本身或者枚举可以发现同样数量的西瓜直接交易比分开交易获得的利润要大,所以就遵循三进制转换的原则,尽量从大的数向下递推。

代码

cpp 复制代码
// Problem: The Cunning Seller (easy version)
// Contest: Virtual Judge - CodeForces
// URL: https://vjudge.net/problem/CodeForces-2132C1#author=GPT_zh
// Memory Limit: 1024 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

void pre()
{
	int k=1;
	a[0]=1;
	for(int i=1; i<=100; i++)
	{
		k*=3;
		a[i]=k;
		if(k>1000000000) break;
	}
}
void solve()
{
	cin >> n;
	int ans=0;	
	for(int i=19; i>=0; i--)
	{
		while(n>=a[i])
		{
			n-=a[i];
			if(i==0)
			{
				ans+=3;
				continue;
			}
			ans+=(i+9)*a[i-1];
		}
	}
	cout << ans << endl;
}

C2. The Cunning Seller (hard version)

思路

这个题有要求即使尽量少的交易次数。此题背景和上次一样,但是上题是说要尽量多的金币, 这题又说要尽量少,而且还要有次数。大方向就是在保证可以刚好分解且在k次交易内的情况下尽量一次交易的少一点。首先先像上一题那样先把最大的可以完全分解的方案给找出来,如果即使是这个方案都超过所给的交易次数的话那么这个方案就不可能,直接输出-1。有最基本的方案之后就要考虑向下递推。每多一层就是原来的三倍,同样的数量就会少用两次交易次数。相反,此时我们要向下递推,每向下一次都会多消耗3-1=2次。也就是说只要此时的交易次数还有两次及以上都可以继续向下进行递推。大概就是这样,剩下的看代码吧。

代码

cpp 复制代码
// Problem: C2. The Cunning Seller (hard version)
// Contest: Codeforces - Codeforces Round 1043 (Div. 3)
// URL: https://codeforces.com/contest/2132/problem/C2
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// Submission Time: 2025-08-22 12:40:17

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int, int>
#define fi first
#define se second 
#define endl '\n'
const int INF = 1e18;
const int N = 50;
int a[N],b[N],c[N];//a[i]:3^i;b[i]:每一层的方案数;c[i]:每一层花费金币数(i+9)*a[i-1]
int n,m,k;
void pre()
{
	int k=1;
	a[0]=1;
	for(int i=1; ; i++)//预处理3^i数组
	{
		a[i]=a[i-1]*3;
		if(a[i]>(int)1e9) break;
	}
}
void solve()
{
	cin >> n >> k;
	int ans=0;	
	memset(b,0,sizeof(b));
	memset(c,0,sizeof(c));
	for(int i=19; i>=0; i--)//求C1题的方案
	{
		while(n>=a[i])
		{
			n-=a[i];
			b[i]++;
			k--;
			if(i==0) ans+=3;
			else ans+=(i+9)*a[i-1];
		}
		if(i==0) c[i]=3;
		else c[i]=(i+9)*a[i-1];
	}
	if(k<0)//正常交易都完成不了
	{
		cout << -1 << endl;
		return ;
	}
	if(k<2)//无法进行贪心
	{
		cout << ans << endl;
		return ;
	}
	// for(int i=0; i<=5; i++) cout << b[i] << ' ';
	for(int i=19; i>=1; i--)
	{
		if(b[i]==0) continue;
		while(k>=2)
		{
			if(b[i]==0||k==0) break;
			if(b[i]*2<=k)//此时剩下交易数足够将这一层全部转移下去
			{
				k-=b[i]*2;//放到下一层交易每次会多两次交易
				ans-=b[i]*c[i];//将该层所有交易金币减去
				ans+=b[i]*3*c[i-1];//本层转移到下层产生的金币数
				b[i-1]+=b[i]*3;//将本层转移到下层
				b[i]=0;//本层没了
				// k--;
				// cout << b[i]*2 << ' ';
				// cout << k << ' ';
			}
			else//此时最高的数量已经足够将剩下交易数耗完,可转移数量为k/2
			{
				ans-=(k/2)*c[i];//原理与上面一样
				ans+=(k/2)*3*c[i-1];
				b[i-1]+=(k/2)*3;
				b[i]-=k/2;
				k=0;
			}
		}
	}
	cout << ans << endl;
	// cout << endl;
	// cout << ans << endl;
	// cout << ans << endl;
	// cin >> n;
	// int k=1;
	// for(int i=1; i<=n; i++)
}
signed main()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int T=1;
	pre();
	cin >> T;
	while(T--) solve();
	return 0;
}