2024.11.23 CodeTON Round 9 (Div. 1 + Div. 2)
Solved:6/11
Rank:135
感觉 F 差一步就做出来了。。。
A. Shohag Loves Mod
题意:给 \(n\),构造一个递增序列使得 \(\{a_i\mod i\}\) 两两不同。
\(\{2i-1\}\)。
#include<bits/stdc++.h>
using namespace std;
void solve(){
int n;
cin>>n;
for(int i=1;i<=n;++i)cout<<i*2-1<<' ';
cout<<'\n';
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);
int T;
cin>>T;
while(T--)solve();
}
B. Shohag Loves Strings
题意:给一个字符串,求任意一个子串使得本质不同子串数量为偶数。
注意到 aa
和 abc
的本质不同子串数都是偶数,而不存在这类子串的字符串只有形如 abababab...
,其所有子串的本质不同子串数均为奇数。
#include<bits/stdc++.h>
using namespace std;
void solve(){
string a;
cin>>a;
int n=a.length();
for(int i=0;i<n-1;++i)if(a[i]==a[i+1]){cout<<a[i]<<a[i+1]<<'\n';return;}
bool fl=0;
for(int i=2;i<n;++i)if(a[i]!=a[i&1])fl=1;
if(!fl){cout<<"-1\n";return;}
for(int i=0;i<n-2;++i)if(a[i]!=a[i+1]&&a[i]!=a[i+2]&&a[i+1]!=a[i+2]){cout<<a[i]<<a[i+1]<<a[i+2]<<'\n';return;}
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);
int T;
cin>>T;
while(T--)solve();
}
C1. Shohag Loves XOR (Easy Version)
题意:给定 \(x,n\),求 \(1\leq y\leq n\) 中有多少个 \(y\) 满足 \((x\oplus y)|x\) 或 \((x\oplus y)|y\)。\(x\leq 10^6, n\leq 10^{18}\)。
当 \(y\) 的二进制最高位比 \(x\) 高时,一定有 \(x\oplus y > x\) 且 \(x\oplus y > \frac y2\)。此时不可能存在整除关系。因此直接从 \(1\) 到 \(\min(n,2^k-1)\) 枚举 \(y\) 即可。这里 \(2^k\) 是 \(2\) 大于 \(x\) 的最小幂次。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve(){
int x;
ll n;
cin>>x>>n;
int m=1;
while(m<=x)m<<=1;
m=min((ll)m,n);
int cnt=0;
for(int i=1;i<=m;++i)if(i!=x){
if(!(x%(x^i))||!(i%(x^i)))++cnt;
}
cout<<cnt<<'\n';
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);
int T;
cin>>T;
while(T--)solve();
}
C2. Shohag Loves XOR (Hard Version)
题意:给定 \(x,n\),求 \(1\leq y\leq n\) 中有多少个 \(y\) 满足 \(x|(x\oplus y)\) 或 \(y|(x\oplus y)\)。\(x\leq 10^6, n\leq 10^{18}\)。
和 C1 类似,当 \(y\) 的二进制最高位比 \(x\) 高时,\(x\oplus y\) 不可能是 \(y\) 的倍数,只可能是 \(x\) 的倍数。问题转化为统计有多少 \(q\) 满足 \(qx\oplus x\leq n\)。当 \(qx\) 与 \(n\) 的 \(k\) 位之前不相等时,\(qx\leq n\) 就等价于 \(qx\oplus x\leq n\),可以直接计算;故只需统计 \(qx\oplus x\) 和 \(n\) 的 \(k\) 位之前相等的情况,这部分可以暴力枚举;另外 \(y\) 很小的部分也可以暴力枚举(注意要减掉重复的)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve(){
int x;
ll n;
cin>>x>>n;
int m=1;
while(m<=x)m<<=1;
if(m>=n){
ll cnt=0;
for(int i=1;i<=n;++i){
if(!((x^i)%i)||!((x^i)%x))++cnt;
}
cout<<cnt<<'\n';
return;
}
ll cnt=0;
for(int i=1;i<m;++i){
if(!((x^i)%i)&&(x^i)%x)++cnt;
}
ll l=n^(n&(m-1)),r=l+m;
cnt+=(l-1)/x;
for(ll y=(l-1)/x*x+x;y<r;y+=x){
if((x^y)<=n)++cnt;
}
cout<<cnt<<'\n';
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);
int T;
cin>>T;
while(T--)solve();
}
D. Shohag Loves GCD
题意:给定 \(n\) 和一个大小为 \(m\) 的集合 \(S\),构造一个序列,满足序列中所有数都属于 \(S\) 且 \(\gcd(a_i,a_j)\neq a_{\gcd(i,j)}, \forall i\neq j\)。
设整数 \(x\) 的质因子数量(计重数)为 \(f(x)\)。当 \(m\leq M=\max_{i=1}^n f(i)\) 时,满足题意的序列一定不存在。
证明:此时一定存在下标序列 \(p_0,p_1,\dots p_M\) 使得 \(p_0|p_1|\dots |p_M\)。根据抽屉原理,一定有两个 \(p_i,p_j\) 满足 \(a_{p_i}=a_{p_j}\),而 \(\gcd(p_i,p_j)=p_i, \gcd(a_{p_i},a_{p_j}) = a_{p_i}\),不合题意。
而另一方面,当 \(m>M\) 时,我们只需将 \(S\) 从大到小排序并令 \(a_i = s_{f(i)}\) 即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define all(x) (x).begin(),(x).end()
const int N=1e5+5;
bool np[N];
int pri[N],cnt,f[N],mx[N];
void sieve(int n){
for(int i=2;i<=n;++i){
if(!np[i])pri[++cnt]=i,f[i]=1;
for(int j=1;j<=cnt&&i*pri[j]<=n;++j){
np[i*pri[j]]=1;
f[i*pri[j]]=f[i]+1;
if(!(i%pri[j]))break;
}
}
for(int i=1;i<=n;++i)mx[i]=max(f[i],mx[i-1]);
}
void solve(){
int n,m;
cin>>n>>m;
vector<int> a(m);
for(int i=0;i<m;++i)cin>>a[i];
if(m<=mx[n]){cout<<"-1\n";return;}
sort(all(a)),reverse(all(a));
for(int i=1;i<=n;++i)cout<<a[f[i]]<<' ';
cout<<'\n';
}
int main(){
sieve(1e5);
ios::sync_with_stdio(0);cin.tie(0);
int T;
cin>>T;
while(T--)solve();
}
E. Shohag Loves Inversions
题意:初始序列为 \([0,1]\),每次可将当前序列的逆序对数插入任意一个位置,求最终能生成的长度为 \(n\) 的序列的数量。对 \(998244353\) 取模。
插入一个数字在绝大多数情况下都会使序列的逆序对数增加。事实上,除了前几次操作插入 \(0,1\) 外,只要序列的逆序对数 \(\geq 2\),那么除非插在序列末尾,插在其他任何位置都会使逆序对数增加。
设 \(f_n\) 为:除末尾相同的和下次插入相等的数外,长度为 \(n+1\),且序列逆序对数 \(\geq 2\) 的方案数。边界为 \(f_1=f_2=0, f_3=2\)。对新插入的数字分三种情况讨论:
-
新的数字是 \(1\) 且插入在前面:手玩可知逆序对数为 \(1\) 的序列只能形如 \(00...01011...1\),能构成的新序列总数为 \(2+3+\dots+(n-1)+n=\frac{(n-1)(n+2)}2\);
-
新的数字 \(\geq 2\) 且插入在前面:由于此时末尾的数都不再是和下次插入相等的数,所以要考虑前面有 \(3\) 到 \(n-1\) 个数的情形,方案总数为 \(\sum_{i=3}^{n-1} (i+1)f_i\)。
-
新的数字 \(\geq 2\) 且插入在末尾:没有贡献。
因此 \(f_n = \frac{(n-1)(n+2)}2 + \sum_{i=3}^{n-1} (i+1)f_i\),答案为 \(n-1+\sum_{i=3}^{n-1} f_i\)(\(n\) 是逆序对数 \(\leq 1\) 的方案数)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define all(x) (x).begin(),(x).end()
const int N=1e6+5,mod=998244353;
int n=1e6;
ll f[N];
int main(){
ios::sync_with_stdio(0);cin.tie(0);
f[1]=0,f[2]=0,f[3]=2;
ll sum=8;
for(int i=4;i<=n;++i){
f[i]=(1ll*(i-2)*(i+1)/2+sum)%mod;
sum=(sum+f[i]*(i+1))%mod;
}
for(int i=4;i<=n;++i)f[i]=(f[i]+f[i-1])%mod;
int T;
cin>>T;
while(T--)cin>>n,cout<<(n-1+f[n-1])%mod<<'\n';
}