Codeforces Round 1065 (Div. 3) A-G
A. Shizuku Hoshikawa and Farm Legs
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
if(n&1){
cout<<0<<endl;
return;
}
cout<<n/4+1<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
}
B. Yuu Koito and Minimum Absolute Sum
观察 \(b\) 数组求和的式子,发现只有 \(a_1,a_n\) 是有用的
所以其他位置填 \(0\),分情况讨论一下 \(a_1,a_n\) 即可
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
if(i!=1 && i!=n && a[i]==-1){
a[i]=0;
}
}
if(a[1]==-1 && a[n]==-1){
a[1]=0,a[n]=0;
}
else if(a[1]==-1){
a[1]=a[n];
}
else if(a[n]==-1)a[n]=a[1];
cout<<abs(a[n]-a[1])<<endl;
for(int i=1;i<=n;i++) cout<<a[i]<<" ";
cout<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
}
C2. Renako Amaori and XOR Game (hard version)
可以从高位到低位去贪心的计算
对于某一位,如果两个数组中这一位的数量和为偶数,则不管怎么交换,\(a,b\) 数组这一位的异或和都相同,此时这一位没有影响,看下一位
如果为奇数,则需要去找最后一个位置,满足 \(a,b\) 两个数,有一个数这一位为 \(1\),另一个数这一位为 \(0\)。谁能操作这个位置,谁就赢
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
vector<int> a(n+1),b(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
}
for(int k=30;k>=0;k--){
int cnt=0;
for(int i=1;i<=n;i++){
// if(((a[i]>>k) & 1)==((b[i]>>k) & 1)){
// continue;
// }
// else cnt++;
cnt+=((a[i]>>k) & 1);
cnt+=((b[i]>>k) & 1);
}
if(cnt%2==0) continue;
for(int i=n;i>=1;i--){
if(((a[i]>>k) & 1)!=((b[i]>>k) & 1)){
if(i&1){
cout<<"Ajisai";
}
else{
cout<<"Mai";
}
cout<<endl;
return;
}
}
}
cout<<"Tie"<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
}
F. Rae Taylor and Trees (hard version)
首先,如果存在位置 \(i\),满足前缀最小值大于后缀最大值,则这个位置的两边无法联通,不能构成树。
否则,可以给出构造方案:
可以找到最小值 \(pos=i\),让最小值去连接 \(i\) 右面的所有数字。
再让 \(pos=i-1\) 的前缀最小值去连接 \(pos=i\) 的后缀最大值
再找到 \(1-(i-1)\) 的最小值 \(j\),令 \(i=j\),不断进行上面的操作,直到连接整个树
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
vector<int> a(n+1),premin(n+1,inf),sufmax(n+2);
vector<int> pos(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
premin[i]=min(premin[i-1],a[i]);
pos[a[i]]=i;
}
for(int i=n;i>=1;i--){
sufmax[i]=max(sufmax[i+1],a[i]);
}
for(int i=1;i<n;i++){
if(premin[i]>sufmax[i+1]){
cout<<"No\n";
return;
}
}
cout<<"Yes\n";
vector<pii> ans;
int p=n;
while(p>1){
int tmp=pos[premin[p]];
for(int i=tmp+1;i<=p;i++){
ans.push_back({a[tmp],a[i]});
}
if(tmp>1) ans.push_back({premin[tmp-1],sufmax[tmp]});
p=tmp-1;
}
for(auto [x,y]:ans){
cout<<x<<" "<<y<<endl;
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
}
E. Anisphia Wynn Palettia and Good Permutations
最优的方式是,使用 \(2\) 和 \(3\) 的倍数,构造:
2_22_22_23_3 这样的,数列,其中 \(2\) 代表 \(2\) 的倍数, \(3\) 代表 \(3\) 的倍数
因为在 \(1\) 到 \(n\) 中,\(2\) 的倍数的个数是 \(n/2\),是\(3\) 的倍数且不是 \(2\) 的倍数的数字个数是 \(n/6\)
相加刚好是 \((2*n)/3\),中间隔出来的空位刚好可以填其他数字
赛时没有发现只使用 \(2,3\) 即可,把 \(1\) 到 \(n\) 所有的质因数都弄了出来,写了一坨,其实代码很好写
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
const int mx=2e5;
vector<int> lp(mx+1),ps(mx+1);
//lp:最小质因子,ps:不同质因子个数
vector<int> primes;
void init(){
for(int i=2;i<=mx;i++){
if(!lp[i]){
lp[i] = i;
primes.push_back(i);
}
for(int p:primes){
if(p>lp[i]||i*p>mx) break;
lp[i*p]=p;
}
}
}
void solve(){
int n;
cin>>n;
vector<int> a(n+1);
int idx=1;
map<int,int> st;
vector<vector<int>> t(n+1);
if(n<=12){
for(int i=1;i<=n;i++){
cout<<i<<" ";
}
cout<<endl;
return;
}
for(auto val:primes){
for(int i=1;val*i<=n;i++){
if(idx>n) break;
if(st[val*i]) continue;
st[val*i]=1;
t[val].push_back(val*i);
}
}
idx=1;
for(auto val:primes){
if(val>n) break;
if(t[val].size()==0) continue;
while(t[val].size()){
if(t[val].size()>1){
if(idx>n) break;
a[idx]=t[val].back();
t[val].pop_back();
idx++;
if(idx>n) break;
a[idx]=t[val].back();
t[val].pop_back();
idx++;
if(t[val].size()>1) idx++;
}
else{
if(idx>n) break;
a[idx]=t[val].back();
idx++;
t[val].pop_back();
}
}
}
st.clear();
for(int i=1;i<=n;i++){
if(a[i]) st[a[i]]=1;
}
vector<int> b;
for(int i=1;i<=n;i++){
if(!st[i]) b.push_back(i);
}
for(int i=1;i<=n;i++){
if(a[i]==0){
a[i]=b.back();
b.pop_back();
}
}
for(int i=1;i<=n;i++) cout<<a[i]<<" ";
cout<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
init();
int t=1;
cin>>t;
while(t--){
solve();
}
}
G. Sakura Adachi and Optimal Sequences
首先,翻倍的操作一定优于单点 \(+1\) 的操作,所以一定要最大化翻倍操作的数量
假设翻倍操作的数量是 \(m\)
则 \(m\) 是满足所有 \(a[i] * 2^m <= b[i]\) 的最大值
确定 \(m\) 后,则尽可能让 \(+1\) 早进行,因为在 \(m\) 次操作前 \(+1\),相当于在 \(m\) 次操作后 \(+~2^m\)
所以从 \(b[i]\) 往 \(a[i]\) 推,如果 \(b[i]\) 是奇数,则不得不进行一次 \(-1\) 操作,否则进行除二操作
至此,可以处理出,\(m\) 次翻倍操作中,每次翻倍操作中间需要 \(cnt[j]\) 次 \(+1\) 操作
还是考虑操作 \(b[i]\),处理完 m 次翻倍后,设此时 \(lft[i]=b[i]-a[i]\)
所以在初始时还需要进行 \(lft[1-n]\) 次 \(+1\) 操作
此时操作次数是固定的,组合数学统计方案数即可
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 1e6+3;
vector<int> fact(mod+3);
int qmi(int a,int b,int p){
int res=1;
while(b){
if(b&1) res=res*a%mod;
b>>=1;
a=a*a%mod;
}
return res;
}
void init(){
int mx=1e6+3;
fact[0]=fact[1]=1;
for(int i=2;i<=mx;i++){
fact[i]=fact[i-1]*i%mod;
}
}
void solve(){
int n;
cin>>n;
vector<int> a(n+1),b(n+1);
int m=inf;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
m=min(m,__lg(b[i]/a[i]));
}
vector<int> cnt(m+1);
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(b[j]&1) cnt[i]++;
b[j]/=2;
}
}
vector<int> lft(n+1);
for(int i=1;i<=n;i++){
lft[i]=b[i]-a[i];
}
int ans1=m;
for(int i=1;i<=n;i++){
ans1+=lft[i];
}
for(int i=1;i<=m;i++){
ans1+=cnt[i];
}
int ans2=1;
for(int i=1;i<=m;i++){
ans2*=fact[cnt[i]];
ans2%=mod;
}
int sum=accumulate(lft.begin()+1,lft.end(),0ll);
if(sum>=mod) ans2=0;
else ans2*=fact[sum];
ans2%=mod;
for(int i=1;i<=n;i++){
ans2*=qmi(fact[lft[i]],mod-2,mod);
ans2%=mod;
}
cout<<ans1<<" "<<ans2<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
init();
int t=1;
cin>>t;
while(t--){
solve();
}
}

浙公网安备 33010602011771号