CF958

爆0的一场,寄寄寄。

A

\(n\)一开始肯定分成\(k\)份,每一份最多增加\(k-1\)。模拟计算即可。

#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
const int MAXN=2e5+10;
const int mod=998244353;
using namespace std;
using ll=long long;
void solve();
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
cin>>t;
while(t--)
{
solve();
}
}
void solve()
{
int n,k; cin>>n>>k;
if(n==1)
{
cout<<0<<"\n";
return;
}
int ans=1;
int sum=k;
while(sum<n)
{
sum+=(k-1);
ans++;
}
cout<<ans<<"\n";
}

B

考虑少了一种情况:11在串中出现两次也是合法。

方法一:分类讨论直接写。

#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
const int MAXN=2e5+10;
const int mod=998244353;
using namespace std;
using ll=long long;
void solve();
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
cin>>t;
while(t--)
{
solve();
}
}
void solve()
{
int n; cin>>n;
string s; cin>>s;
if(n==1)
{
if(s=="1") cout<<"YES\n";
else cout<<"NO\n";
return;
}
if(s[0]=='0' && s[n-1]=='0')
{
int cnt=0;
int cnt_1=1;
int maxn=0;
for(int i=0;i<n-1;i++)
{
if(s[i]==s[i+1] && s[i]=='1')
{
cnt_1++;
}
else
{
if(cnt_1>1)
{
cnt++;
}
maxn=max(cnt_1,maxn);
cnt_1=1;
}
}
if(maxn>2 || cnt>1) cout<<"YES\n";
else cout<<"NO\n";
}
else if(s[0]=='1' && s[n-1]=='1')
{
cout<<"YES\n";
}
else if(s[0]=='0' && s[n-1]=='1')
{
for(int i=0;i<n-1;i++)
{
if(s[i+1]==s[i] && s[i]=='1')
{
cout<<"YES\n";
return;
}
}
cout<<"NO\n";
}
else if(s[0]=='1' && s[n-1]=='0')
{
reverse(s.begin(),s.end());
for(int i=0;i<n-1;i++)
{
if(s[i+1]==s[i] && s[i]=='1')
{
cout<<"YES\n";
return;
}
}
cout<<"NO\n";
}
}

方法二:可以想到应该尽可能地少让1和0进行操作,应该尽量让全0串化为一个0。那么最终结果就会使一个由孤立0和1(连续或者不连续)组成的串。如果0的个数小于1则有解,否则无解。

#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
const int MAXN=2e5+10;
const int mod=998244353;
using namespace std;
using ll=long long;
void solve();
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
cin>>t;
while(t--)
{
solve();
}
}
void solve()
{
int n; cin>>n;
string s; cin>>s;
int one=count(s.begin(),s.end(),'1');
int zero=0;
for(int i=0;i<s.size();i++)
{ //用连续0串的开头进行记录zero
if(s[i]=='0' && (i==0 || s[i-1]=='1'))
{
zero++;
}
}
if(zero<one)
{
cout<<"YES\n";
}
else
{
cout<<"NO\n";
}
}

C

观察样例发现都是以\(n\)结尾的,我们以样例四进行研究。

14: 1 1 1 0

要使得单增,并且最长,且\(a_{i}|a_{i-1}=n (2\leq i \leq k)\),我们进行倒推,那么第二大应该越大越好,同理推导下去。

14: 1 1 1 0
1 1 0 0
1 0 1 0
0 1 1 0

可以发现推导的结果如上。可以发现:从小到大,0一直在右移。我们可以统计\(n\)的组成,并且模拟这个过程,逐个进行计算输出。不过需要注意一些情况需要特判。

如果原来的数只有一个1(二进制),那么直接输出即可。

#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
const int MAXN=2e5+10;
const int mod=998244353;
using namespace std;
using ll=long long;
void solve();
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
cin>>t;
while(t--)
{
solve();
}
}
void solve()
{
ll n; cin>>n;
// 1 1 1 0
// 1 1 0 0
// 1 0 1 0
// 0 1 1 0
vector<ll> a;
int k=0;
ll m=n;
int cnt=0;
while(n)
{
if(n&1)
{
a.push_back(k);
}
n>>=1;
k++;
}
//cout<<a.size()<<"a size:";
if(a.size()==1)
{
cout<<1<<"\n";
cout<<m<<"\n";
return;
}
cout<<a.size()+1<<"\n";
cnt=a.size()-1;
for(int i=0;i<a.size();i++)
{
ll ans=0;
for(int j=0;j<a.size();j++)
{
if(j!=cnt)
{
ans+=(1ll<<a[j]);
}
}
cout<<ans<<" ";
cnt--;
}
cout<<m<<"\n";
}

另外一种写法:

可以发现我们可以使用位运算进行操作,只需要获取是哪个位置的1,并且进行异或运算即可。

#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
const int MAXN=2e5+10;
const int mod=998244353;
using namespace std;
using ll=long long;
void solve();
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
cin>>t;
while(t--)
{
solve();
}
}
void solve()
{
ll n; cin>>n;
int one=__builtin_popcountll(n);
if(one==1)
{
cout<<1<<"\n"<<n<<"\n";
return;
}
cout<<one+1<<"\n";
for(int i=63;i>=0;i--)
{
if((n>>i) & 1)
{
cout<<(n^(1ll<<i))<<" ";
}
}
cout<<n<<"\n";
}