2025牛客寒假算法基础集训营5
状态最拉跨的一场,很难受,脑袋转不动
A
注意数据范围,简单构造
J
按照题意模拟
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int t;
int n,m;
string s;
void solve(){
cin>>n;
cin>>s;s=" "+s;
int v=0;
long long ans=0;
for(int i=1;i<=n;++i){
if(s[i]=='0'){
v+=10;
ans+=v;
}
else if(s[i]=='1'){
v=max(v-5,0);
ans+=v;
}
else {
if(v<10) continue;
ans+=(v-10);
}
}
cout<<ans<<endl;
return ;
}
int main(){
t=1;
while(t--){
solve();
}return 0;
}
B
其实就是问一个长度为n的木块切割成最多长度大于等于t的小木块,一定有k个切割点,切割点占一个长度
贪心:
尽可能的切割更多,所以每个小木块保持最短t
如果可以切割成小木棍数量多于k个切割点,那么最多可以k+1个棍子
否则尽可能的切割成(n-k)/t个,多余的切割点放在最后
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int _;
int n,t,k;
void solve(){
cin>>n>>t>>k;
int cnt=(n-k)/t;
if(cnt>k){
cnt=k+1;
}
cout<<cnt<<endl;
}
int main(){
cin>>_;
while(_--){
solve();
}return 0;
}
I
玄学猜测题
有时候不能理解这样的题是为了什么,考验提交代码的勇气?
当然可能是数学直觉
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int t;
int n,m;
void solve(){
cin>>n>>m;
if(n==0 || m==0){
if(m!=n) puts("No");
else puts("Yes");
return ;
}
else puts("Yes");
}
int main(){
cin>>t;
while(t--){
solve();
}return 0;
}
做法开个数组统计行列的X棋子数量,同行行列有O让数量为负,代表无法连成三个
-
很显然,如果只下了1或者2步棋,必胜
-
如果只下了3步棋,那么输的情况只有类似于
-
空了一行或一列,且其他行如一下排列的棋局
(样例给的不错OXX , OXO
XOO , XOX
GGG , GGG
只要确保某行某列某斜线棋子数量一定是2就行
-
如果空的是斜线,那么分为两种情况
-
X在另一个斜线上,且周边没有X,不赢
GOX
XGO
OXG
-
X在另一个斜线上,周边有X,必赢
还是一个道理只要确保某行某列某斜线棋子数量大于1就行
-
-
那么再考虑,空的不连续的情况,只需要验证,某一行还是某一列,还是某个斜线有一个X就可以了,且没有O,即大于等于1
3.下了4步棋,只需要找到某行某列某斜线数量为2就行
所以只需要找棋子数量>0就行
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int t;
map<int,int> mp[5];
void solve(){
int cnt=0;
mp[1].clear();mp[2].clear();
for(int i=1;i<=3;++i)
for(int j=1;j<=3;++j){
char p;cin>>p;
if(p=='G') continue;
++cnt;
mp[1][i]+=(p=='X')?1:-5;
mp[2][j]+=(p=='X')?1:-5;
if(i+j==4)mp[1][i+j]+=(p=='X')?1:-5;
if(i-j==0)mp[1][i-j]+=(p=='X')?1:-5;
}
bool book=0;
int res=0;cnt/=2;
for(int i=1;i<=3;++i)
for(auto [x,y]:mp[i])
if(y>0) book=1;
if(cnt<=2) puts("Yes");
else {
if(book)puts("Yes");
else puts("No");
}
}
int main(){
cin>>t;
while(t--){
solve();
}
return 0;
}
C
很容易知道是贪心,但是怎么去贪,才是这个题的难点
而且题目已知,交换次数和取反的次数与最终的值有关,而这里有两种方式,我们则需要尽量睿智地选择一种方式
- 当时,这时,只取反肯定是最好的选择
- 否则尽量选择交换
讨论交换的情况:
对于a,b异或与c相同的,我们不予考虑
对于a,b异或与c不同的,我们发现有四种情况
- a:0,b:0
- a:0,b:1
- a:1,b:0
- a:1,b:1
我们发现任意两两之间,都可以选择a或b交换,可以使得异或正确(可以试着枚举一下
这时,
- 如果其中一种情况大于其他三种,那么就可以用该种情况与其他的两两交换,剩下的就取反
- 否则,就两两之间相互抵消,如果是奇数,最后剩下的一个取反
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
string a,b,c;
int n;
const int maxn=1e6+10;
int x,y;
ll cnt[5];
int main(){
cin>>n>>x>>y;
cin>>a>>b>>c;
for(int i=0;i<n;++i){
if(c[i]==(a[i]==b[i]?'0':'1')) continue;
cnt[0]+=(a[i]=='0' && b[i]=='0');
cnt[1]+=(a[i]=='0' && b[i]=='1');
cnt[2]+=(a[i]=='1' && b[i]=='0');
cnt[3]+=(a[i]=='1' && b[i]=='1');
}
sort(cnt,cnt+4);
ll sum=0;
for(int i=0;i<4;++i) sum+=cnt[i];
ll ans=(sum)*x;
if(cnt[3]>sum-cnt[3])//一个情况大于另外三种
ans=min(ans,(ll)(sum-cnt[3])*y+(2*cnt[3]-sum)*x);
else {
ans=min(ans,(ll)sum/2*y+sum%2*x);
}
cout<<ans<<endl;
return 0;
}
L
构造,找一个三元组,恰好两对互质,且每个数只能用一次
显然,无解
当时,我们能找到最小元素组成的三元组是
当时
有个常用结论:连续的数互质
为了保证三元组在n的范围内取到最多,所以从小开始取
我们可以找到满足条件,而也是满足条件的,所以这两个三元组是连续的6个数
此时,是奇数,可以推得上式正确
但这里需要注意,当时,还会多出一组三元组
我们提前找出前9个数的合法三元组,这样后续的三元组就可以按照连续6个数的方式取
而这时的三元组,以x=10为开头,,是偶数,所以
是正确的连续三元组
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int t;
int n;
void solve(){
cin>>n;
if(n<=3){
cout<<0<<endl;
return ;
}
cout<<n/3<<endl;
if(n<6)
{
cout<<"2 3 4"<<endl;
return;
}
else {
if((n/3)%2==0){
for(int i=1;i+5<=n;i+=6){
cout<<i<<" "<<i+1<<" "<<i+3<<"\n";
cout<<i+2<<" "<<i+4<<" "<<i+5<<"\n";
}
}
else {
puts("1 2 4");
puts("3 9 5");
puts("6 8 7");
for(int i=10;i+5<=n;i+=6){
cout<<i+1<<" "<<i+2<<" "<<i+5<<"\n";
cout<<i<<" "<<i+3<<" "<<i+4<<"\n";
}
}
}
}
signed main(){
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--){
solve();
}
return 0;
}
D
区间内,可0变1,1变0,且可以任意排列
所以一个长度为的区间,可以等效为等四种情况
所以在排列每个区间时,为了尽可能减小对答案的贡献,我们可以使区间衔接处相等(一定可以,因为0和1之间可以转化),而只有区间内不同时则一定会对答案贡献+1
因此,只需要统计区间内是否全部相同就能判断对答案的贡献
注意,如果全部相同,那贡献为1
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n;
int ans=0;
string s;
const int maxn=1e6+10;
int pre[maxn];
int main(){
cin>>n;
cin>>s;s=" "+s;
for(int i=1;i<=n;++i) pre[i]=pre[i-1]+(s[i]=='1');
for(int k=1;k<=n;++k){
int cnt=1;
for(int i=1;i<=n;i+=k){
int l=i,r=min(n,l+k-1);
cnt+=(pre[r]-pre[l-1]<r-l+1 && pre[r]>pre[l-1]);
}
ans^=cnt;
}
cout<<ans<<endl;
}
本文作者:归游
本文链接:https://www.cnblogs.com/guiyou/p/18705407
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步