Codeforces Round 1043 (Div. 3)
Codeforces Round 1043 (Div. 3)
(https://codeforces.com/contest/2132)
赛时 \(5\) 题,不知道是最近懈怠了还是感冒没好全,出了 \(E\) 就想下班了。
A
solution
按题意模拟,将给定字符贴到原字符串的左右。
因为 \(n+m \le 20\),可以用 std::string
直接复制。
code
void func(void)
{
int n,m;
string st,s1,s2;
cin >> n >> st >> m >> s1 >> s2;
for(int i=0;i<m;++i)
{
if(s2[i] == 'V') st = s1[i] + st;
else st += s1[i];
}
cout << st << '\n';
}
B
solution
\(y\) 是\(x\)在右边添加正数个 \(0\),那么:\(y = x \times 10^{t}\)
\(x+y = (10^t + 1)x = n\)
因为 \(n \le 10^{18}\),枚举 \(1 \sim 18\) 即可得到答案
记得开 longlong
code
void func(void)
{
int n;
cin >> n;
int z = 10;
vector<int> ans;
for(int i=0;i<18;++i,z*=10)
{
if(n%(z+1) == 0) ans.push_back(n/(z+1));
}
sort(ans.begin(),ans.end());
cout << ans.size() << '\n';
for(int i=0;i<ans.size();++i) cout << ans[i] << " \n"[i==ans.size()-1];
}
C1
C1 C2不是不同范围的同一题,不能用C2代码过C1
solution
事实上这题就是将 \(n\) 转成三进制,然后求各位 \(\times 3^{x+1} + x \cdot 3^{x-1}\) 的和。
code
void func(void)
{
int _3[21];
_3[0] = 1;
for(int i=1;i<=20;++i) _3[i] = _3[i-1]*3;
int n;
cin >> n;
int ans = 0;
for(int i=19;i>=1;--i)
{
if(n >= _3[i])
{
ans += n/_3[i]*(_3[i+1]+i*_3[i-1]);
n %= _3[i];
}
}
if(n) ans += n*3;
cout << ans << '\n';
}
C2
solution
将上一题最小化交易次数,改为求次数 \(k\) 内最小支付。
在出售一个西瓜时,需要支付 \(3^{0} + 0 = 3\) 块钱。
那么购买 \(3^x\) 西瓜,需要多支付 \(3^{x+1} + x \cdot 3^{x-1} - 3^{x+1} = x \cdot 3^{x-1}\)
这是一个单调增函数,\(x\) 越大,多支付的钱越多。
那么我们直接贪心,每次把 \(x\) 最大的交易转换为 \(3\) 次 \(x-1\)的交易,直到达到 \(k\) 次交易的上限,或者只剩下 \(x = 0\) 的交易(买一个瓜)为止。
然后根据每个 \(x\) 交易的次数求结果即可。
我们可以直接在C1的代码上修改:
- 将各位加入答案,改为存储各位的值
- 从大到小将 \(x\) 转化为 \(x-1\)
将一次 \(x\) 转换为三次 \(x-1\),实际增加了 \(3-1 = 2\) 次交易。 - 最后根据各位的值求解结果即可,
code
void func(void)
{
_3[0] = 1;
for(int i=1;i<=20;++i) _3[i] = _3[i-1]*3;
int n,k;
cin >> n >> k;
int ans = 0;
vector<int> a(20);
for(int i=19;i>=1;--i)
{
if(n >= _3[i])
{
a[i] = n/_3[i];
k -= a[i];
n %= _3[i];
}
}
a[0] = n;
k -= a[0];
if(k < 0)
{
cout << "-1\n";
return;
}
for(int i=19;i>=1;--i)
{
int z = (k >= a[i]*2 ? a[i] : k/2);
a[i] -= z, k -= z*2;
a[i-1] += z*3;
ans += a[i]*(_3[i+1]+i*_3[i-1]);
}
ans += a[0]*3;
cout << ans << '\n';
}
D
赛时没出,感觉比E难
补题感觉这题还是挺简单了,果然是当时脑子糊涂了
solution
基本思路是
- 计算 \(k\) 对应到是第 \(n\) 个数
- 计算前 \(n-1\) 个数各位之和
- 计算第 \(n\) 个数前几位的和
个位数占 \(9\) 位,十位数占 \(2 \times 9 \times 10\),百位数占 \(3 \times 9 \times 10^2\)
以此类推,\(t\) 位数占 \(t \times 9 \times 10^{t-1}\)
那么我们可以算出 \(n\) 对应几位数,以及之前有多少个数字。
然后因为在这之后的数都是 \(t\) 位数,直接除以 \(t\) 就可以得出后续又有多少数,加起来就是 \(k\) 之前有多少数。
然后我们来计算这 \(n\) 个数的各位和
我们对每个位单独分析:
- 个位是以 \(10\) 为周期的等差数列,\(0,1,2,3,\ldots,9\),一个周期的和为 \(45\)
- 十位是以 \(100\) 为周期的等差数列,\(\overbrace{0,0,\ldots,0}^{10 个},\overbrace{1,1,\ldots,1}^{10 个},\ldots,\overbrace{9,9,\ldots,9}^{n 个}\),,一个周期的和为 \(450\)
- 以此类推,\(t\) 位是以 \(2^{t+1}\) 为周期的等差数列,一个周期的和为 \(45\times10^{t-1}\)
因为我们是从 \(1\) 开始,统计各个数都缺少一位,所以我们可以加上一个 \(0\),然后假设求的是该情况下 \(k+1\) 位数。
这时候再对最后这个不一定完整的数求前余下位的和即可,总操作不超过 \(15\) 次
code
代码可能会有一些省略或者不同,但是意思是相同的
void func(void)
{
int n; cin >> n;
int stp = 1, t = 1;
int ans = 0;
int k = 1;
while(true)
{
if(t*stp*9 > n) break;
n -= t*stp*9;
k += stp*9;
stp *= 10, t ++;
}
k += (n/t);
n %= t;
for(int i=0,p=1;i<=t;++i,p*=10)
{
ans += k/(p*10)*45*p;
int tmp = k%(p*10);
for(int j=0;j<=9;++j)
{
if(tmp < p)
{
ans += tmp*j;
break;
}
tmp -= p;
ans += p*j;
}
}
string st = to_string(k);
for(int i=0;i<n;++i) ans += (st[i]-'0');
cout << ans << '\n';
}
E
排序 \(+\) 前缀和计数
赛时推反了式子多卡 \(20min\),引以为戒
solution
出于贪心,我们必然尽可能拿 \(a,b\) 所有数中最大的 \(z\) 个数。
我们记前 \(z\) 个数中,\(a\) 中的有 \(cnt_a\) 个,\(b\) 中的有 \(cnt_b\) 个。
那么我们开始分类讨论,注意 \(x+y \ge z, cnt_a + cnt_b = z\)
- 若是 \(cnt_a \le x \wedge cnt_b \le y\) 我们可以取出 \(cnt_a + cnt_b = z\)
- 若是 \(cnt_a > x \wedge cnt_b \le y\) 我们从 \(a\) 中取出只能取出 \(x\) 个数,然后从 \(b\) 中取 \(z-x\) 个数补齐
- 若是 \(cnt_a \le x \wedge cnt_b > y\) 我们从 \(b\) 中取出只能取出 \(y\) 个数,然后从 \(a\) 中取 \(z-y\) 个数补齐
- 不存在 \(cnt_a > x \wedge cnt_b > y\)
code
void func(void)
{
int n,m,q;
cin >> n >> m >> q;
int L = n+m;
vector<int> a(n+1), b(m+1), ca(L+1), cb(L+1), sa(n+1), sb(m+1);
vector<PII> sr(L+1);
for(int i=1;i<=n;++i)
{
cin >> a[i];
sr[i] = {a[i],1};
}
for(int i=1;i<=m;++i)
{
cin >> b[i];
sr[n+i] = {b[i],-1};
}
sort(a.begin()+1,a.end(),greater<int>());
sort(b.begin()+1,b.end(),greater<int>());
sort(sr.begin()+1,sr.end(),greater<PII>());
for(int i=1;i<=n;++i) sa[i] = sa[i-1] + a[i];
for(int i=1;i<=m;++i) sb[i] = sb[i-1] + b[i];
for(int i=1;i<=L;++i)
{
ca[i] = ca[i-1], cb[i] = cb[i-1];
sr[i].Y == 1 ? ca[i] ++ : cb[i] ++;
}
while(q --)
{
int x,y,z; cin >> x >> y >> z;
if(ca[z] <= x)
{
if(cb[z] <= y) cout << sa[ca[z]] + sb[cb[z]] << '\n';
else cout << sa[z-y] + sb[y] << '\n';
}
else cout << sa[x] + sb[z-x] << '\n';
}
}
other
先发这些,等睡醒再补FG