2024.12.19 Codeforces Global Round 28
Solved: 6/10
A. Kevin and Combination Lock
题意:给一个整数,每次你可以将它减 33 或擦掉一个 33,问能否变成 0。
注意到擦掉 33 不会改变原数模 3 和 11 的余数,因此只需判断原数能否被 33 整除。
#include<bits/stdc++.h>
using namespace std;
void solve(){
int n;
cin>>n;
cout<<(n%33?"NO":"YES")<<'\n';
}
int main(){
int T;
cin>>T;
while(T--)solve();
}
B. Kevin and Permutation
题意:构造一个排列 \(p\),使得 \(\sum_{i=1}^{n-k+1}\min_{j=1}^{j+k-1}p_j\) 最小。
每隔 \(k\) 个位置放尽量小的数即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve(){
int n,k;
cin>>n>>k;
vector<int> a(n+1);
int j=1;
for(int i=k;i<=n;i+=k)a[i]=j,++j;
for(int i=1;i<=n;++i)if(!a[i])a[i]=j,++j;
for(int i=1;i<=n;++i)cout<<a[i]<<' ';
cout<<'\n';
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);
int T;
cin>>T;
while(T--)solve();
}
C. Kevin and Binary Strings
题意:给一个 01 串,找出两个子串使得它们的异或和最大。\(|s|\leq 5000\)
因为位数越多越大,所以其中一个子串必为整个串。而另一个串需要高位尽可能是 1。原串的前几个 1 显然可以保留,找到从高位开始第一个 0 的位置,从这一位开始的长度就是第二个串的长度。因为 \(n^2\) 可过,所以直接枚举第二个串的起始位置即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve(){
string a;
cin>>a;
int n=a.length(),pos=-1;
for(int i=0;i<n;++i)a[i]-='0';
for(int i=0;i<n;++i)if(!a[i]){pos=i;break;}
if(pos==-1){cout<<1<<' '<<n<<' '<<1<<' '<<1<<'\n';return;}
string mx="";
int ans=0;
for(int j=0;j<pos;++j){
string s=a;
for(int k=0;k<n-pos;++k)s[pos+k]^=a[j+k];
if(s>mx)mx=s,ans=j;
}
cout<<1<<' '<<n<<' '<<ans+1<<' '<<ans+n-pos<<'\n';
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);
int T;
cin>>T;
while(T--)solve();
}
D. Kevin and Competition Memories
题意:\(n\) 个人,第 \(i\) 个人水平为 \(a_i\),\(m\) 道题,第 \(j\) 道题难度为 \(b_j\)。每个人能做出且仅能做出 \(b_j\leq a_i\) 的题。
每场比赛 \(k\) 道题,举办 \(\lfloor mk\rfloor\) 场比赛,每道题只能供一场比赛。\(n,m\leq 3\times 10^5\)
对每个 \(k\),求所有比赛第 \(1\) 个人排名之和的最小值。
考虑每个人对答案的贡献。设满足 \(a_1<b_j\leq a_i\) 的 \(j\) 共有 \(t_i\) 个,则
\(t_i\) 可以排序后双指针求,处理贡献时可用整除分块+差分数组优化为 \(O(\sqrt m)\)。总复杂度 \(O(n\sqrt m)\)。
好像有点卡常(赛时提交 1900+ms)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define all(x) (x).begin(),(x).end()
void solve(){
int n,m;
cin>>n>>m;
vector<int> a(n),b(m);
for(int& x:a)cin>>x;
for(int& x:b)cin>>x;
int a0=a[0];
sort(all(a)),sort(all(b));
int cnt=0,p=n,q=m;
for(int i=0;i<n;++i)if(a[i]>a0){p=i;break;}
for(int i=0;i<m;++i)if(b[i]>a0){q=i;break;}
vector<ll> s(m+2);
for(int i=p,j=q;i<n;++i){
while(j<m&&b[j]<=a[i])++j;
int t=m-(j-q);
for(int l=1,r;l<=t;l=r+1){
r=t/(t/l);
s[l]-=t/l,s[r+1]+=t/l;
}
}
for(int i=1;i<=m;++i)s[i]+=s[i-1];
for(int i=1;i<=m;++i)s[i]+=1ll*(n-p+1)*(m/i),cout<<s[i]<<' ';
cout<<'\n';
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);
int T;
cin>>T;
while(T--)solve();
}
E. Kevin and Bipartite Graph
题意:完全二分图 \(K(2n,m)\),给每条边染色为 \(n\) 种颜色,给出染色方案使得不存在同色环。
纯试出来的构造,不知道有没有更简洁的方法。
\(2n\leq m\) 无解,直接输出 NO。
以 \(n=4\) 为例:
1 1 2 3 4 2 3 4
2 2 3 4 1 3 4 1
3 3 4 1 2 4 1 2
4 4 1 2 3 1 2 3
1 2 3 4 1 2 3 4
2 3 4 1 2 3 4 1
3 4 1 2 3 4 1 2
4 1 2 3 4 1 2 3
取前 \(m\) 列。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define all(x) (x).begin(),(x).end()
void solve(){
int n,m;
cin>>n>>m;
if(n*2<=m){
cout<<"NO\n";
return;
}
vector<vector<int>> a(2*n);
for(int i=0;i<2*n;++i)a[i].resize(2*n);
for(int i=0;i<n;++i){
a[i][0]=a[i][1]=i;
for(int j=0;j<n;++j)a[n+i][j]=a[n+i][n+j]=(i+j)%n;
for(int j=1;j<n;++j)a[i][j+1]=a[i][j+n]=(i+j)%n;
}
cout<<"YES\n";
for(int i=0;i<n*2;++i,cout<<'\n')
for(int j=0;j<m;++j)
cout<<a[i][j]+1<<' ';
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);
int T;
cin>>T;
while(T--)solve();
}
F. Kevin and Math Class
题意:给两个序列 \(a\) 和 \(b\)。每次操作可以选择一个区间 \([l,r]\),令 \(x=\min_{j=l}^r b_j\),然后对每个 \(l\leq i\leq r\) 令 \(a_i\leftarrow \lceil\frac{a_i}x\rceil\)。问最少几次操作可使序列 \(a\) 全为 \(1\)。\(n\leq 2\times 10^5, a_i\leq 10^{18}\)。
容易发现
- 总操作数不超过 \(\log w\leq 60\)。
- 操作顺序一定是从小区间到大区间,除的数从大到小。
对 \(b\) 序列建立笛卡尔树,设 \(f(u,k)\) 表示以 \(u\) 为顶点的子树共操作 \(k\) 次最大值的最小值。则有转移
分两步转移,总复杂度 \(O(n\log^2 w)\)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define all(x) (x).begin(),(x).end()
const int N=2e5+5;
int n;
ll a[N],b[N];
int st[20][N];
int mini(int i,int j){
return b[i]<=b[j]?i:j;
}
int qmni(int l,int r){
int o=__lg(r-l+1);
return mini(st[o][l],st[o][r-(1<<o)+1]);
}
ll f[N][60];
int rt,lc[N],rc[N];
int bld(int l,int r){
int mid=qmni(l,r);
lc[mid]=mid>l?bld(l,mid-1):0;
rc[mid]=mid<r?bld(mid+1,r):0;
return mid;
}
void dfs(int u){
if(lc[u])dfs(lc[u]);
if(rc[u])dfs(rc[u]);
memset(f[u],0x3f,sizeof(ll)*60);
for(int i=0;i<60;++i)
for(int j=0;i+j<60;++j)
f[u][i+j]=min(f[u][i+j],max(a[u],max(f[lc[u]][i],f[rc[u]][j])));
ll g[60];
memset(g,0x3f,sizeof(ll)*60);
for(int i=0;i<60;++i){
ll t=f[u][i];
for(int j=0;i+j<60;++j)
g[i+j]=min(g[i+j],t),t=(t+b[u]-1)/b[u];
}
memcpy(f[u],g,sizeof(ll)*60);
}
void solve(){
cin>>n;
for(int i=1;i<=n;++i)cin>>a[i];
for(int i=1;i<=n;++i)cin>>b[i],st[0][i]=i;
for(int i=1;1<<i<=n;++i)
for(int j=1;j+(1<<i)-1<=n;++j)
st[i][j]=mini(st[i-1][j],st[i-1][j+(1<<i-1)]);
rt=bld(1,n);
dfs(rt);
for(int i=0;i<60;++i)if(f[rt][i]==1){cout<<i<<'\n';return;}
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);
int T;
cin>>T;
while(T--)solve();
}