2025.1.20 IAEPC Preliminary Contest (Codeforces Round 999, Div. 1 + Div. 2)

比赛链接

Solved: 6/11

Rank: fst,寄!

B 先读错题再 fst,绷不住了。。。


A. Kevin and Arithmetic

题意:给一个序列,初始 s=0。对 i=1,,n 依次进行如下操作:ss+ai,然后若 s 为偶数则分数 +1 并不断除 2 直到 s 为奇数。重排序列使得分数最高。

偶数除了第一个以外其他都不会产生贡献,答案就是奇数个数加 1。特判所有数都是奇数的情况。

void solve(){
int n;
cin>>n;
vector<int> a(n);
cin>>a;
int cnt=0;
for(int i=0;i<n;++i)if(a[i]&1)++cnt;
cout<<(n==cnt?n-1:cnt+1)<<'\n';
}

B. Kevin and Geometry

题意:给 n 个数,选出其中 4 个数使得它们可以组成等腰梯形。

设四条边长度为 a,b,c,c,且 a<b,则充要条件是 ba<2c

将所有数排序后枚举相等的数 c,判断剩下的数里是否有差小于 2c 的两个数即可。这个可以用差分数组前后缀的 min 做。

fst 因:没考虑 a<c<b 的情况!

void solve(){
int n;
cin>>n;
vector<int> a(n);
cin>>a;
sort(all(a));
vector<int> b(n-1);
for(int i=0;i<n-1;++i)b[i]=a[i+1]-a[i];
vector<int> p(n-1),s(n-1);
for(int i=0;i<n-1;++i){
if(i==0)p[i]=b[i];
else p[i]=min(p[i-1],b[i]);
}
for(int i=n-2;i>=0;--i){
if(i==n-2)s[i]=b[i];
else s[i]=min(s[i+1],b[i]);
}
for(int i=0;i<=n-2;++i)if(a[i]==a[i+1]){
if(i>1&&p[i-2]<a[i]*2){
for(int j=0;j<=i-2;++j)if(b[j]==p[i-2]){
cout<<a[j]<<' '<<a[j+1]<<' '<<a[i]<<' '<<a[i+1]<<'\n';
return;
}
}
if(i<n-3&&s[i+2]<a[i]*2){
for(int j=n-2;j>=i+2;--j)if(b[j]==s[i+2]){
cout<<a[j]<<' '<<a[j+1]<<' '<<a[i]<<' '<<a[i+1]<<'\n';
return;
}
}
if(i>=1&&i<=n-3&&a[i+2]-a[i-1]<a[i]*2){
cout<<a[i-1]<<' '<<a[i]<<' '<<a[i+1]<<' '<<a[i+2]<<'\n';
return;
}
}
cout<<"-1\n";
}

upd: 其实只要令 c 为最大的两个相等的数,然后排剩下的检查每相邻两个就行。。。


C. Kevin and Puzzle

题意:n 个人站成一排,其中有一部分人是说谎者。每个人会给出站在自己左侧的说谎者的数量 ai,说谎者提供的 ai 不可信(不一定错误),相邻两个人不可能都是说谎者。问这 n 个人的身份的方案数。

dp,f(i,0/1) 表示 i 说真话/假话的方案数。如果 i 说真话,需要 ai=ai1i1 真)或 ai=ai2+1i1 假)。

void solve(){
int n;
cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;++i)cin>>a[i];
vector<array<ll,2>> f(n+1);
f[0][0]=1;
for(int i=1;i<=n;++i){
if(a[i]==a[i-1])f[i][0]=(f[i][0]+f[i-1][0])%mod;
if(i==1||a[i]==a[i-2]+1)f[i][0]=(f[i][0]+f[i-1][1])%mod;
f[i][1]=(f[i][1]+f[i-1][0])%mod;
}
cout<<(f[n][0]+f[n][1])%mod<<'\n';
}

D. Kevin and Numbers

题意:给两个集合 AB。每次可以在 A 中选择两个差不超过 1 的数合并为它们的和,问能否变成 B

逆向思考。如果 B 的最大值 xA 中不存在,那么它一定是通过 x2x2 合成得到的。如果存在,则一定是 A 中相同的数直接保留。

用 multiset 模拟这个逆向过程即可。

bool solve(){
int n,m;
cin>>n>>m;
multiset<int> a,b;
ll s=0;
for(int i=0,x;i<n;++i)cin>>x,a.insert(x),s+=x;
for(int i=0,x;i<m;++i)cin>>x,b.insert(x),s-=x;
if(s)return false;
while(a.size()&&b.size()){
int x=*a.rbegin(),y=*b.rbegin();
if(x>y)return false;
if(x==y){
a.erase(a.find(x));
b.erase(b.find(y));
}
else{
b.erase(b.find(y));
b.insert(y/2);
b.insert((y+1)/2);
}
}
return a.empty()&&b.empty();
}

E. Kevin and And

题意:有两个集合 AB。你可以做 k 次操作,每次选择 aiA,bjB 并令 aiai&bj。问操作结束后 A 所有数之和的最小值。n105,m10

首先可以 O(n2m) 求出 A 中每个数做 110 次操作得到的最小值。对于单个 i,操作的收益是单调减的,因此可以用堆维护这个操作过程。复杂度 O(n2m+klogn)

const int N=1e5+5,M=10;
int n,m,q,d[N];
ll a[N],b[M],c[1<<M],f[N][M+1];
void solve(){
cin>>n>>m>>q;
for(int i=1;i<=n;++i)cin>>a[i];
for(int i=0;i<m;++i)cin>>b[i];
for(int i=0;i<1<<m;++i){
c[i]=(1<<30)-1;
for(int j=0;j<m;++j)if(i>>j&1)
c[i]&=b[j];
}
for(int i=1;i<=n;++i){
for(int j=0;j<=m;++j)f[i][j]=0;
for(int j=0;j<1<<m;++j){
int k=__builtin_popcount(j);
f[i][k]=max(f[i][k],a[i]-(a[i]&c[j]));
}
}
priority_queue<pll> pq;
ll ans=0;
for(int i=1;i<=n;++i)pq.push({f[i][1],i}),ans+=a[i],d[i]=0;
while(q--){
int i=pq.top().second;
ans-=pq.top().first;
pq.pop();
++d[i];
if(d[i]<m)pq.push({f[i][d[i]+1]-f[i][d[i]],i});
}
cout<<ans<<'\n';
}

F1. Kevin and Binary String (Easy Version)

题意:给定 01 串 s,t,每次可以交换 s 相邻的极长 0 连续段和极长 1 连续段,求最少交换次数使 s 变成 t。若无法做到则输出 -1

首先在 st 的开头都插入一个 t1,结尾都插入一个 tn,答案不变。

插入之后,每次操作都恰好会减少两个极长连续段。因此答案就是极长连续段数之差除 2。我们只需判断能否做到。

s 的极长连续段长为 a1,,am。如果我们交换 s 的第 i 段和第 i+1 段,实际上就是令 aiai+ai+2,ai+1ai+1+ai+3
因此直接在 st 的极长连续段长序列上双指针枚举,如果相等就匹配,如果不相等就尝试交换操作。

如果你 WA4 了,请注意 aibj 匹配上了并不代表 ai+1 也要和 bj+1 匹配。

const int N=4e5+5;
int n,m1,m2,a[N],b[N];
string s,t;
int solve(){
cin>>s>>t;
n=s.length();
char u=t[0],v=t[n-1];
s=u+s+v,t=u+t+v,n+=2;
int len=0;
m1=m2=0;
for(int i=0;i<n;++i){
if(i>0&&s[i]!=s[i-1])a[++m1]=len,len=1;
else ++len;
}
a[++m1]=len;
len=0;
for(int i=0;i<n;++i){
if(i>0&&t[i]!=t[i-1])b[++m2]=len,len=1;
else ++len;
}
b[++m2]=len;
int i=1,j=1;
while(j<=m2){
if(i>m1)return -1;
if(b[j]<a[i])return -1;
if(b[j]==a[i]){++i,++j;continue;}
if(i==m1)return -1;
int x=a[i],y=a[i+1];
if(j+1<=m2){
while(i+3<=m1){
x+=a[i+2],y+=a[i+3],i+=2;
if(x>b[j])return -1;
if(x==b[j])break;
}
if(x==b[j])++i,++j,a[i]=y;
else return -1;
}
else return -1;
}
if(i>m1)return (m1-m2)/2;
else return -1;
}
posted @   EssnSlaryt  阅读(342)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示