2022-11-15 16:19阅读: 207评论: 0推荐: 0

Codeforces Round #833 (Div. 2)

A. The Ultimate Square (CF 1748 A)

题目大意

给定n块板,第i块板的宽为 1,长为 i2。问用这些板可以组成一个正方形,问其最大的边长是多少。

解题思路

题意可以相当于给定了长度为1n2板各两个。

n是奇数时,第一块板和第 n1块板组合,第二块板和第n2块板组合,刚好组成n12 块长度为n2板,加上第 n块板刚好可以组成长度为 n2的正方形

n是偶数时直接前后组合,也同样可以组成长度为n2的正方形。

因此答案就是 n2

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int t;
cin >> t;
while(t--){
int x;
cin >> x;
cout << (x + 1) / 2 << '\n';
}
return 0;
}


B. Diverse Substrings (CF 1748 B)

题目大意

给定一个仅包含数字的字符串,问其有多少个子串,记cnti表示数字 i的出现次数, up为不同数字的个数,满足所有数字 i均有 cntiup

解题思路

注意数字种类只有10个,因此合法串的长度最长也就 100,因此对长度为 1 100的所有子串暴力 判断即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int t;
cin >> t;
while(t--){
int n;
cin >> n;
string s;
cin >> s;
LL ans = 0;
for(int i = 0; i < s.size(); ++ i){
map<int, int> qwq;
set<int> ff;
auto check = [&](){
for(auto &i : qwq)
if (i.second > ff.size())
return false;
return true;
};
for(int j = 1; j <= 100; ++ j){
int r = i + j - 1;
if (r >= s.size())
break;
ff.insert(s[r]);
qwq[s[r]] ++;
if (check())
++ ans;
}
}
cout << ans << '\n';
}
return 0;
}


C. Zero-Sum Prefixes (CF 1748 C)

题目大意

给定一个长度为n的整数组 a,可以将其中为0的项变为任意数字,问其前缀和为0的最大数量是多少,即最大化满足以下条件的k的数量,使得 i=0kai=0

解题思路

即前缀和sumk=i=0kai

从左到右考虑每个0,假设当前考虑的下标是 i,其值为0, 下一个0的下标为j。考虑对前者的0更改其值,将影响sumi,...,j1的值,即这些值中出现次数最多的是 val,很显然我们将 0变成 val,这样就尽可能有更多的前缀和为 0,同时也不影响 sumj...n(该相同的还是相同)。

因此统计每两个0相邻之间前缀和出现最多的次数即可。注意别忘了第一个0出现前前缀和为0的数量。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int t;
cin >> t;
while(t--){
int n;
cin >> n;
vector<int> a(n);
for(auto &i : a)
cin >> i;
bool zero = false;
map<LL, LL> cnt;
LL ans = 0;
LL sum = 0;
for(int i = 0; i < n; ++ i){
sum += a[i];
if (a[i] == 0 && zero){
LL id = 0, val = 0;
for(auto &i : cnt){
if (val < i.second){
val = i.second;
id = i.first;
}
}
sum -= id;
ans += val;
cnt.clear();
}else if (a[i] == 0){
zero = true;
cnt.clear();
}else if (!zero && sum == 0)
++ ans;
cnt[sum] ++;
}
if (zero){
LL id = 0, val = 0;
for(auto &i : cnt){
if (val < i.second){
val = i.second;
id = i.first;
}
}
sum -= id;
ans += val;
}
cout << ans << '\n';
}
return 0;
}


D. ConstructOR (CF 1748 D)

题目大意

给定a,b,d,要求给一个 x<260,满足

  • a|xd整除
  • b|xd整除

其中|为二进制或运算

其中a,b,d<230

解题思路

构造题,尽量从简入手。

不妨假设a|x=b|x=x。由于x<260,而 a|b<230,我们考虑高30 位,可以列出以下方程

x=t×230+(a|b)0modd

如果d是偶数, 2是不存在逆元的,如果此时 (a|b)是奇数,那么该方程无解。但如果是偶数,我们可以所有数提一个 2出来,此时方程的成立条件并不会变化,可以继续相同判断。

假设提了 c2,方程就变为

x=t×230c+(a|b)0modd

此时必有一个数是奇数,如果(a|b)是奇数则无解,如果 d是奇数,则可解出t=inv(2)30c(a|b)

继而得到 x

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
LL qpower(LL a, LL b, LL mo){
LL qwq = 1;
while(b){
if (b & 1)
qwq = qwq * a % mo;
a = a * a % mo;
b >>= 1;
}
return qwq;
}
LL exgcd(LL a, LL b, LL &x, LL &y) {
if (b == 0) { x = 1; y = 0; return a; }
LL ret = exgcd(b, a % b, y, x);
y -= a / b * x;
return ret;
}
LL get_inv(LL a, LL M) {
static LL x, y;
assert(exgcd(a, M, x, y) == 1);
return (x % M + M) % M;
}
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int t;
cin >> t;
while(t--){
LL a, b, d;
cin >> a >> b >> d;
bool ok = true;
int sign = 0;
while(!(d & 1)){
if ((a & 1) || (b & 1)){
ok = false;
break;
}
d >>= 1;
a >>= 1;
b >>= 1;
++ sign;
}
if (!ok)
cout << "-1" << '\n';
else{
LL ab = (a | b);
LL m = d - ab % d;
LL x = m * qpower(get_inv(2, d), 30 - sign, d) % d;
x <<= 30;
x += (ab << sign);
cout << x << '\n';
}
}
return 0;
}


E. Yet Another Array Counting Problem (CF 1748 E)

题目大意

给定一个整数序列a,记f(l,r)表示子序列 a[l..r]中值最大且下标最小的下标。

问有多少个整数序列 b,其 f(l,r)a相同。其中 1bim

解题思路

又是最值又是下标,容易想到笛卡尔树,实际上就是问有多少个序列b的笛卡尔树和序列 a一样。

dp[i][j]表示下标为i取值为j的方案数,在笛卡尔树上直接dp即可。

dp[i][j]=k=1j1dp[lson[i]][k]×l=1jdp[rson[i]][l]

转移的时候记录下前缀和就好了。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
#define FOR(i, x, y) for (decay<decltype(y)>::type i = (x), _##i = (y); i < _##i; ++i)
#define FORD(i, x, y) for (decay<decltype(x)>::type i = (x), _##i = (y); i > _##i; --i)
const int N = 1e6 + 8;
const LL mo = 1e9 + 7;
int n, rt, m;
LL val[N], ans;
LL G[N][2];
void build() {
static int s[N], last;
int p = 0;
FOR (x, 1, n + 1) {
last = 0;
while (p && val[s[p - 1]] < val[x]) last = s[--p];
if (p) G[s[p - 1]][1] = x;
if (last) G[x][0] = last;
s[p++] = x;
}
rt = s[0];
}
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int t;
cin >> t;
while(t--){
cin >> n >> m;
for(int i = 1; i <= n; ++ i)
cin >> val[i];
build();
vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
function<void(int)> dfs = [&](int u){
if (G[u][0] == 0 && G[u][1] == 0){
fill(dp[u].begin(), dp[u].end(), 1);
return;
}
LL lsum = 0, rsum = 0;
LL lson = G[u][0];
if (lson != 0)
dfs(lson);
LL rson = G[u][1];
if (rson != 0)
dfs(rson);
for(int i = 1; i <= m; ++ i){
rsum += dp[rson][i];
rsum %= mo;
dp[u][i] = (lson == 0 ? 1 : lsum) * (rson == 0 ? 1 : rsum) % mo;
lsum += dp[lson][i];
lsum %= mo;
}
};
dfs(rt);
ans = 0;
for(int i = 1; i <= m; ++ i)
ans = (ans + dp[rt][i]) % mo;
cout << ans << '\n';
for(int i = 0; i <= n; ++ i)
G[i][0] = G[i][1] = 0;
}
return 0;
}


本文作者:~Lanly~

本文链接:https://www.cnblogs.com/Lanly/p/16892830.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   ~Lanly~  阅读(207)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.