集训5 20240209
牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ
A:
题目大意:给出一个整数和一个操作符,生成两个能组成这个数的因子
#include<bits/stdc++.h>
#define cintie ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;int main()
{long long x;char op;cin>>x>>op;if (op=='*'){cout<<x<<' '<<1<<endl;}if (op=='+'){cout<<x-1<<' '<<1<<endl;}if (op=='-'){cout<<x+1<<' '<<1<<endl;}return 0;
}
签到模拟
J:
题目大意:给出一个字符串,根据字符的不同计算总路程,不同字符表示对速度的不同操作
#include<bits/stdc++.h>
#define cintie ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;int main()
{int n;cin>>n;long long ans=0,v=0;vector<char> op(n+5);for (int i=1;i<=n;i++) cin>>op[i];for (int i=1;i<=n;i++){if (op[i]=='0'){v+=10;ans+=v;}if (op[i]=='1'){if (v-5>=0){v-=5;ans+=v;}else{v=0;ans+=v;}}if (op[i]=='2'){if (v-10>0){v-=10;ans+=v;v+=10;}else{int t=v;v=0;ans+=v;v=t;}}}cout<<ans<<endl;return 0;
}
v
记录当前的速度,ans
存答案,乱模拟就行
B:
题目大意:有 \(n\) 个元素,其中存在 \(k\) 个元素被标记,\(t\) 个以上没有被标记的连续元素为一组,排列被标记的数后求分组的最大数量
#include<bits/stdc++.h>
#define cintie ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;long long n,t,k;bool judge(long long x){if (t*x+k<=n)return 1;elsereturn 0;
}void solve(void){cin>>n>>t>>k;long long lb=(t+1)*k;if (lb<=n){if (n-lb>=t)cout<<k+1<<endl;elsecout<<k<<endl;}else{long long l=-1,r=k+1;while (l+1!=r){long long mid=l+r>>1;if (judge(mid))l=mid;elser=mid;}cout<<l<<endl;}
}int main()
{int T;cin>>T;while(T--)solve();return 0;
}
原本想得太复杂了卡了 \(4\) 发,最终的代码虽然正确但是不够简单,用了二分来算
实际上仔细审视这个问题,将 \(k\) 个被标记的元素去除后我们还能用 \(n-k\) 个元素,那么这些元素可以分出 \(\lfloor\frac{n-k}{t}\rfloor\) 组
但是这 \(k\) 个被标记的元素最多能将这 \(n\) 个元素分为 \(k+1\) 组
所以只需要简单的判断最小值即可
void solve() {int n, t, k;cin >> n >> t >> k;cout << min(k+1,(n-k)/t)<<endl;
}
I:
题目大意:给出两个数 \(n,m\) 可以进行两种操作
- 将 \(n\) 乘以二
- 将 \(n\) 开方后向下取整
判断是否能通过以上两种操作使 \(n\) 变为 \(m\)
#include<bits/stdc++.h>
#define cintie ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;void solve(void){int n,m;cin>>n>>m;if (n==0&&m!=0||m==0&&n!=0){cout<<"NO"<<endl;return;}cout<<"YES"<<endl;return;
}int main()
{int T;cin>>T;while (T--)solve();return 0;
}
猜的结论,当且仅当 \(n,m\) 中仅有一个为 \(0\) 时才不能转变,否则一定能组合出答案
证明如下:
存在一个数 \(x\)
取对数后,不等式转化为
所以一定存在正整数 \(m\) 使得 \(x=2^m\) ,\(x\) 经过多次操作可以得到 \(y\)
C:
题目大意:
#include<bits/stdc++.h>
#define cintie ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;long long n,x,y;int main()
{cin>>n>>x>>y;string a,b,c;cin>>a>>b>>c;int cnt[4]={0};for (int i=0;i<n;i++){if (((a[i]-'0')^(b[i]-'0'))!=(c[i]-'0')){if (a[i]=='0'&&b[i]=='0') cnt[0]++;if (a[i]=='0'&&b[i]=='1') cnt[1]++;if (a[i]=='1'&&b[i]=='0') cnt[2]++;if (a[i]=='1'&&b[i]=='1') cnt[3]++;}}long long ans=1ll*x*(cnt[0]+cnt[1]+cnt[2]+cnt[3]);sort(cnt,cnt+4);if (cnt[3]>cnt[0]+cnt[1]+cnt[2]){ans=min(ans,(cnt[0]+cnt[1]+cnt[2])*y+(cnt[3]-cnt[0]-cnt[1]-cnt[2])*x);}else{ans=min(ans,(cnt[0]+cnt[1]+cnt[2]+cnt[3])/2*y+(cnt[0]+cnt[1]+cnt[2]+cnt[3])%2*x);}cout<<ans<<endl;return 0;
}
核心想法:分别记录 a^b!=c
的四种情况的种数
if (a[i]=='0'&&b[i]=='0') cnt[0]++;
if (a[i]=='0'&&b[i]=='1') cnt[1]++;
if (a[i]=='1'&&b[i]=='0') cnt[2]++;
if (a[i]=='1'&&b[i]=='1') cnt[3]++;
\(0\oplus0=1\oplus1=0,0\oplus1=1\oplus0=1\),那么这四种情况有一个潜在的性质
假设 \(a\oplus b=1\) ,将 \(a,b\) 中任一元素取反后,\(a\oplus !b=!a\oplus b=!1=0\)
特别的对于两个不同的 a,b
元素组,如果它们都不匹配 c
,我们一定可以交换其中某一位 \(0,1\) 来使得这两个都能匹配 c
首先计算如果全部都采用替换的办法,那么需要的代价总值为 x*(cnt[0]+cnt[1]+cnt[2]+cnt[3])
然后考虑可以交换的情况:对这四种情况按数量进行排序
- 如果一种情况比其余情况都要多,那么只用考虑其余情况和最多的情况进行交换操作,剩下的就进行替换
- 如果如果一种情况比其余情况要少,进行交换后要么刚好可以两两抵消,要么剩下一组,这一组单独进行替换即可(组数为奇数)
if (cnt[3]>cnt[0]+cnt[1]+cnt[2]){//cnt[3]>(cnt[0]+cnt[1]+cnt[2]+cnt[3])/2,大于总数的一半ans=min(ans,(cnt[0]+cnt[1]+cnt[2])*y+(cnt[3]-cnt[0]-cnt[1]-cnt[2])*x);
}else{ans=min(ans,(cnt[0]+cnt[1]+cnt[2]+cnt[3])/2*y+(cnt[0]+cnt[1]+cnt[2]+cnt[3])%2*x);
}
还有两题,挖坑后补