[ICPC2024 Xi'an I] ICPC2024 邀请赛西安站重现赛 / The 2024 ICPC China Shaanxi National Invitational Programming Contest
M. Chained Lights
参考洛谷某题解
首先,进行偶数次完全相同的操作相当于没做。
将 press[1] 单独拎出来:
light[1]^=1;
for(int i=2;i<=n;i++){
press(i);
}
然后,会进行:
for(int i=2;i<=n;i++){
press(i);
}
会发现,只有第一个位置是 1,其他都是 0
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
using ll=long long;
using pii=pair<int,int>;
const ll inf = 1e18;
const int mod = 1e9+7;
void solve(){
int n,k;
cin>>n>>k;
cout<<((k==1)?"YES":"NO");
cout<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--) solve();
return 0;
}
J. Triangle
对每一行去二分一个位置就好了,需要推一下数学式子
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
using ll=long long;
using pii=pair<int,int>;
const ll inf = 1e18;
const int mod = 1e9+7;
void solve(){
int a,b;
cin>>a>>b;
int ans=0;
for(int i=0;i<a;i++){
double low=i,high=i+1;
auto check=[&](int x)->bool {
double l=x-1,r=x;
if(x==0) return 1;
double y1=((-a)*l+a*b)/b;
double y2=((-a)*r+a*b)/b;
if(y1<=low) return 0;
if(y1>=high){
if(y2>=low) return 1;
}
if(y1>=low && y1<=high && y2<=low) return 0;
double x1=b*(a-high)/a;
double x2=b*(a-low)/a;
return ((x1+x2-2*l)/2ll>=0.5);
};
int l=0,r=b;
while(l<r){
int mid=l+r+1>>1;
if(check(mid)) l=mid;
else r=mid-1;
}
ans+=r;
}
cout<<ans;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--) solve();
return 0;
}
F. XOR Game
本质还是奇偶数博弈。
最关键的点:对于大于等于 2 的位置,归属一定是固定的。
所以两人只会轮流去拿等于 1 的位置
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
using ll=long long;
using pii=pair<int,int>;
const ll inf = 1e18;
const int mod = 1e9+7;
void solve(){
int k,z;
cin>>k>>z;
vector<int> ans(k+1),b(k+1);
int sum=z;
for(int i=1;i<=k;i++){
cin>>b[i];
sum+=b[i];
}
b[0]=z;
vector<int> t;
for(int i=0;i<=k;i++){
if(b[i]==0) continue;
if(b[i]==1){
t.push_back(i);
}
else{
if(sum&1) ans[i]=1;
else ans[i]=0;
}
}
while(t.size()){
auto p=t.back();
t.pop_back();
ans[p]=1;
if(t.size()) t.pop_back();
}
for(int i=k;i>=1;i--){
cout<<ans[i];
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--) solve();
return 0;
}
D. Make Them Straight
Tag: 优化枚举,调和级数
枚举公差 \(k\),对于每一个位置,可以根据 \(k\) 反推出一个 \(a[1]\),这意味着,如果把 \(a[1]\) 修改为这个位置反推出的 \(a[1]\),则这个位置不用变化,否则这个位置需要变化。
对于每一个 \(k\),可以得到很多个反推出的 \(a[1]\),枚举这些 \(a[1]\),计算答案。
计算 \(a[i]\) 的公式是:\(a[i]-(i-1)*k\),而当 \((i-1)*k\) 大于 \(1e6\) 时,结果一定非法,此时可以结束本次 \(k\) 的循环
对于 \(k=i\) 时,循环会进行 \(1e6/i\) 次,所以是个调和级数的复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
using ll=long long;
using pii=pair<int,int>;
const ll inf = 1e18;
const int mod = 1e9+7;
void solve(){
int n;
cin>>n;
vector<int> a(n+1),b(n+1),sufb(n+2);
int sum=0;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
sum+=b[i];
}
for(int i=n;i>=1;i--){
sufb[i]=sufb[i+1]+b[i];
}
int ans=inf;
//当公差是时,如果首项是 i,则代价是 sum-t[i]
vector<int> t(1e6+1);
for(int k=0;k<=1e6;k++){
int must=0;
for(int i=1;i<=n;i++){
if((i-1)*k>1e6){
break;
}
int now=a[i]-(i-1)*k;
if(now<0) continue;
else t[now]+=b[i];
ans=min(ans,sum-t[now]);
}
for(int i=1;i<=n;i++){
if((i-1)*k>1e6){
break;
}
int now=a[i]-(i-1)*k;
if(now<0) continue;
else t[now]-=b[i];
}
}
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--) solve();
return 0;
}
L. Rubbish Sorting
对于一个长度的为 \(5\) 的字符串,每个为有 \(0\) 或 \(a-z\) 共 \(27\) 个选择,所以最多有 \(27^5≈1.5e7\) 种不同的字符串
对于每个操作 \(1\),假设字符串的长度为 \(n\), 对于每个位置可以选或不选,最终得到 \(2^n\) 个字符串,然后用当前的类型去更新这这些字符串的类型
对于每个操作 \(1\),假设字符串的长度为 \(n\), 对于每个位置可以选或不选,最终得到 \(2^n\) 个字符串,枚举这些字符串,找一个最大相似度且类型最小的即可
点击查看代码
#include<bits/stdc++.h>
// #define int long long
#define endl '\n'
using namespace std;
using ll=long long;
using pii=pair<int,int>;
const ll inf = 1e9+7;;
const int mod = 1e9+7;
const int N=2e7;
vector<int> type(N,inf);
void solve(){
int q;
cin>>q;
while(q--){
int ch,x;
string s;
cin>>ch>>s;
if(ch==1){
cin>>x;
for(int i=0;i<32;i++){
int pos=0,now=1;
for(int j=0;j<s.size();j++){
int val=0;
if((i>>j) & 1) val=s[j]-'a'+1;
else val=0;
pos+=val*now;
now*=27;
}
type[pos]=min(x,type[pos]);
}
}
else{
int sim=-1,ans=0;
for(int i=0;i<32;i++){
int pos=0,now=1,cnt=0;
for(int j=0;j<s.size();j++){
int val=0;
if((i>>j) & 1){
val=s[j]-'a'+1;
cnt++;
}
else val=0;
pos+=val*now;
now*=27;
}
if(type[pos]==inf) continue;
if(cnt>sim){
sim=cnt;
ans=type[pos];
}
else if(cnt==sim){
ans=min(ans,type[pos]);
}
}
cout<<ans<<endl;
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--) solve();
return 0;
}
I. Smart Quality Inspector
tag: 状压DP
对于 \(k\) 个数,从大到小去填。
设 \(f[mask]\)表示,此时已经从大到小填了 \(popcount(mask)\) 个数,这些数填的位置压缩成二进制是 \(mask\),此时的最小值是多少
转移时,可以枚举 \(mask\) 中的每一个是 \(1\) 的位置, 从去掉这一位的 \(f\) 转移过来。
设这个位置是 \(p\),设 \(l,r\) 分别为在当前填法 \(mask\) 中,左右第一个已经被填的数 (在 \(mask\) 的二进位中,左右第一个是 1 的位置)
因为是从大到小去填数,所以将本次的数填到位置 \(p\) 后,仅仅会对完全在 \((l,r)\) 范围内,且跨越 \(p\) 的区间产生贡献。 这个东西可以通过一个类似二维前缀和的形式预处理出来
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
using ll=long long;
using pii=pair<int,int>;
const ll inf = 1e18;
const int mod = 1e9+7;
int pct(int x){
return __builtin_popcount(x);
}
void solve(){
int n,k,m;
cin>>n>>k>>m;
vector<vector<int>> seg(n+1,vector<int>(n+1));
for(int i=1;i<=m;i++){
int a,b;
cin>>a>>b;
a--,b--;
seg[a][b]++;
}
for(int len=2;len<=n;len++){
for(int i=0;i+len-1<n;i++){
int j=i+len-1;
seg[i][j]+=seg[i+1][j]+seg[i][j-1]-seg[i+1][j-1];
}
}
//f[mask]:填数方式是 mask ( popcnt(mask)<=k ) 时,的最小值
vector<int> f(1<<n,inf);
f[0]=0;
int ans=inf;
auto cal=[&](int l,int r)->int {
//计算有多少个区间落在 [l,r] 中
if(l > r || l < 0 || r >= n) return 0;
return seg[l][r];
};
for(int i=1;i<(1<<n);i++){
if(pct(i)>k) continue;
for(int p=0;p<n;p++){
if((i>>p) & 1){
int prestate=f[i^(1<<p)];
int l=p,r=p;
while(l>0 && (i>>(l-1) & 1) == 0){
l--;
}
while(r<n-1 && (i>>(r+1) & 1) == 0){
r++;
}
int val=k-pct(i) +1;
//g[l,r] - g[l,p-1] - g[p+1,r]
f[i]=min(f[i],prestate+val*(cal(l,r)-cal(l,p-1)-cal(p+1,r)));
}
}
if(pct(i)==k) ans=min(ans,f[i]);
}
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--) solve();
return 0;
}

浙公网安备 33010602011771号