Codeforces Round 1016 (Div. 3) A-F(略讲)G(详解)
A. Ideal Generator
\(判断奇偶即可\)
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int mod=998244353;
int gcd(int a,int b){return b?gcd(b,a%b):a;};
int qpw(int a,int b){int ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
int inv(int x){return qpw(x,mod-2);}
void solve(){
int n;cin>>n;
if (n&1) {
cout<<"YES\n";
}else cout<<"NO\n";
}
signed main(){
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int _=1;
cin>>_;
while(_--)solve();
}
\(前缀零保存求最小删除个数\)
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int mod=998244353;
int gcd(int a,int b){return b?gcd(b,a%b):a;};
int qpw(int a,int b){int ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
int inv(int x){return qpw(x,mod-2);}
void solve(){
string s;cin>>s;
int cnt=s.size()-1;
int mi=1e9;
for (int i=0;i<s.length();i++) {
if (s[i]=='0')cnt--;
else mi=min(mi,cnt);
}
cout<<mi<<endl;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int _=1;
cin>>_;
while(_--)solve();
}
C. Simple Repetition
\(只有1为特殊情况 其他情况必定存在类似于10101的格式能够为其的第二个因数 分类讨论一下即可\)
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int mod=998244353;
int gcd(int a,int b){return b?gcd(b,a%b):a;};
int qpw(int a,int b){int ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
int inv(int x){return qpw(x,mod-2);}
void solve(){
int x,k;cin>>x>>k;
if (x==1) {
for (int i=2;i<=k;i++) {
x=x*10+1;
}
k=1;
}
if (k>1||x==1) {
cout<<"NO\n";return;
}else {
for (int i=2;i*i<=x;i++) {
if (x%i==0) {
cout<<"NO\n";return;
}
}
}
cout<<"YES\n";
}
signed main(){
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int _=1;
cin>>_;
while(_--)solve();
}
D. Skibidi Table
\(分型板子题 将其每个部分进行讨论\)
\(发现个数和4^n相关\)
\(位置和2^n相关\)
\(根据题目给出的图做即可\)
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int mod=1e18;
int gcd(int a,int b){return b?gcd(b,a%b):a;};
int qpw(int a,int b){int ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
int inv(int x){return qpw(x,mod-2);}
int pw[100];
void solve(){
function<void(int,int,int,int)>dfs1=[&](int now,int x,int y,int n) {
if (n==-1) {
cout<<x<<" "<<y<<'\n';return;
}
if (now>3*pw[2*n]) {
dfs1(now-3*pw[2*n],x,y+pw[n],n-1);
}else if (now>2*pw[2*n]) {
dfs1(now-2*pw[2*n],x+pw[n],y,n-1);
}else if (now>pw[2*n]) {
dfs1(now-1*pw[2*n],x+pw[n],y+pw[n],n-1);
}else dfs1(now,x,y,n-1);
};
function<void(int,int,int,int)>dfs2=[&](int x,int y,int n,int now) {
if (n==-1) {
cout<<now<<'\n';return;
}
if (x>pw[n]&&y>pw[n]) {
dfs2(x-pw[n],y-pw[n],n-1,now+pw[2*n]);
}else if (x>pw[n]) {
dfs2(x-pw[n],y,n-1,now+2*pw[2*n]);
}else if (y>pw[n]) {
dfs2(x,y-pw[n],n-1,now+3*pw[2*n]);
}else {
dfs2(x,y,n-1,now);
}
};
int n,q;cin>>n>>q;
while (q--) {
string s;cin>>s;
if (s=="<-") {
int d;cin>>d;
dfs1(d,1,1,n);
}else {
int x,y;cin>>x>>y;
dfs2(x,y,n,1);
}
}
}
signed main(){
pw[0]=1;
for (int i=1;i<=60;i++)pw[i]=pw[i-1]*2;
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int _=1;
cin>>_;
while(_--)solve();
}
E. Min Max MEX
\(过于简单 二分答案\)
\(因为连续 所以每次存满就清空即可\)
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int mod=1e18;
int gcd(int a,int b){return b?gcd(b,a%b):a;};
int qpw(int a,int b){int ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
int inv(int x){return qpw(x,mod-2);}
void solve(){
int n,k;cin>>n>>k;
vector<int>a(n+1);
for (int i=1;i<=n;i++)cin>>a[i];
auto ck=[&](int x) {
vector<int>vis(x+1);
int mex=0;
int cnt=0;
int pos=0;
for (int i=1;i<=n;i++) {
if (a[i]<=x)vis[a[i]]=i;
while (mex<=x&&vis[mex]>pos)mex++;
if (mex>=x)cnt++,mex=0,pos=i;
}
return cnt>=k;
};
int l=0,r=(n+1)/k+1;
int ans;
while (l<=r) {
int mid=(l+r)>>1;
if (ck(mid)) {
ans=mid;
l=mid+1;
}else r=mid-1;
}
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int _=1;
cin>>_;
while(_--)solve();
}
F. Hackers and Neural Networks
\(除了题目难读一点没有难度 将最大个数匹配满 此时使用了n的次数\)
\(然后对于剩余的位置都需要先清空在加入即可\)
\(答案即为n+(n-mx)*2\)
\(特判不成立情况即可\)
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int mod=1e18;
int gcd(int a,int b){return b?gcd(b,a%b):a;};
int qpw(int a,int b){int ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
int inv(int x){return qpw(x,mod-2);}
void solve(){
int n,m;cin>>n>>m;
vector<vector<string>>b(m,vector<string>(n));
vector<string>a(n);
vector<int>vis(n);
int mx=0;
for (int i=0;i<n;i++)cin>>a[i];
for (int i=0;i<m;i++) {
int cnt=0;
for (int j=0;j<n;j++) {
cin>>b[i][j];
if (b[i][j]==a[j])vis[j]=1,cnt++;
}
mx=max(mx,cnt);
}
for (int i=0;i<n;i++) {
if (!vis[i]) {
cout<<-1<<'\n';return;
}
}
cout<<n+(n-mx)*2<<'\n';
}
signed main(){
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
int _=1;
cin>>_;
while(_--)solve();
}
G. Shorten the Array
\(VP时被卡空间了(热)\)
Shorten the Array
题目描述
给定一个长度为 \(n\) 的数组 \(a\),定义子数组的 美丽值 \(f(b)\) 为子数组 \(b\) 中所有可能的数对 \((b_i, b_j)\) 的异或值的最大值,即:
\[f(b) = \max_{1 \leq i \leq j \leq m} (b_i \oplus b_j)
\]
其中 \(\oplus\) 表示按位异或操作。
我们称一个子数组 \(b\) 是 美丽的,如果其美丽值满足 \(f(b) \geq k\)。现在需要在一个数组 \(a\) 中找到最短的美丽子数组。如果不存在这样的子数组,则输出 \(-1\)。
算法分析
关键问题
-
如何快速计算子数组的最大异或值:
- 暴力枚举所有子数组并计算最大异或值的时间复杂度为 \(O(n^3)\),显然不可行。
- 我们需要一种高效的数据结构来维护当前子数组中的元素,并快速查询是否存在两个元素的异或值大于等于 \(k\)。
-
如何判断异或值是否满足条件:
- 利用按位异或的性质:从高位到低位逐位匹配,可以快速判断是否存在满足条件的数对。
-
如何优化子数组长度的搜索:
- 使用滑动窗口思想,结合高效的查询数据结构(如 01 Trie),动态维护当前子数组的元素和查询结果。
核心思路
-
使用 01 Trie 维护子数组元素:
- 01 Trie 是一种二叉树结构,用于高效存储和查询二进制表示的数字。
- 每次插入新元素时,将其二进制表示逐位插入到 Trie 中,同时记录每个节点对应的最新位置。
-
基于 Trie 的异或值查询:
- 对于当前元素 \(x\),从高到低逐位检查是否存在某个已插入的元素 \(y\),使得 \(x \oplus y \geq k\)。
- 如果 \(k\) 的某一位为 \(1\),则必须匹配该位为 \(1\) 的分支;否则优先尝试匹配该位为 \(1\) 的分支以最大化异或值。
-
滑动窗口更新最小长度:
- 动态维护当前子数组的最小长度,每次插入新元素后查询是否存在满足条件的数对,更新答案。
-
终止条件:
- 如果最终没有找到满足条件的子数组,则输出 \(-1\)。
复杂度证明
-
时间复杂度:
- 每个元素插入到 01 Trie 中的时间复杂度为 \(O(31)\)(因为整数最多有 31 位)。
- 查询操作同样为 \(O(31)\)。
- 总时间复杂度为 \(O(n \cdot 31) = O(n)\)。
-
空间复杂度:
- 01 Trie 的节点总数最多为 \(O(n \cdot 31)\),因此空间复杂度为 \(O(n)\)。
代码实现
以下是完整的 C++ 实现代码:
#include<bits/stdc++.h>
#define all(x) (x).begin(),(x).end()
#define rall(x) (x).rbegin(),(x).rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
void solve() {
int n, k;
cin >> n >> k;
// 定义变量
int cnt = 0; // 当前 Trie 节点计数
auto get_pos = [&](int x, int y) {
return (n * 31 + 1) * y + x; // 计算 Trie 节点的唯一标识
};
vector<int> nxt(n * 62 + 1); // 存储 Trie 的子节点指针
vector<int> pos(n * 62 + 1); // 存储每个节点对应的位置
// 插入函数:将元素 x 插入到 Trie 中
auto insert = [&](int x, int P) {
int p = 0; // 从根节点开始
for (int i = 30; i >= 0; i--) { // 从高位到低位逐位插入
int c = x >> i & 1; // 获取当前位的值
if (!nxt[get_pos(p, c)]) nxt[get_pos(p, c)] = ++cnt; // 创建新节点
p = nxt[get_pos(p, c)]; // 移动到子节点
pos[p] = P; // 更新节点的最新位置
}
};
// 查询函数:查找是否存在满足条件的数对
auto get = [&](int x, int r) {
int p = 0; // 从根节点开始
int ok = 0; // 是否找到满足条件的数对
int mi = n + 1; // 最小子数组长度
for (int i = 30; i >= 0; i--) { // 从高位到低位逐位匹配
int c = (x >> i & 1) ^ 1; // 尝试匹配异或值为 1 的分支
if (k >> i & 1) { // 如果 k 的当前位为 1
if (!nxt[get_pos(p, c)]) return mi; // 无法匹配,返回当前最小值
p = nxt[get_pos(p, c)]; // 必须匹配该分支
} else { // 如果 k 的当前位为 0
if (nxt[get_pos(p, c)]) { // 如果存在异或值为 1 的分支
mi = min(mi, r - pos[nxt[get_pos(p, c)]] + 1); // 更新最小长度
}
if (!nxt[get_pos(p, c ^ 1)]) return mi; // 无法继续匹配,返回当前最小值
p = nxt[get_pos(p, c ^ 1)]; // 移动到另一分支
}
}
mi = min(mi, r - pos[p] + 1); // 更新最小长度
return mi;
};
vector<int> a(n + 1); // 存储输入数组
int len = n + 1; // 初始化最小长度为无穷大
for (int r = 1; r <= n; r++) {
cin >> a[r];
insert(a[r], r); // 插入当前元素
len = min(len, get(a[r], r)); // 查询并更新最小长度
}
if (len == n + 1) cout << -1 << '\n'; // 如果未找到满足条件的子数组
else cout << len << '\n'; // 输出最小长度
}
signed main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int _ = 1;
cin >> _;
while (_--) solve();
}

浙公网安备 33010602011771号