题意:可以通过选取下标不同的两个数,使其中一个数的值增加,另一个数的值减小。问:反复操作后高度差最小为?
思路:答案只可能为0或1。当所有数之和能被数字的个数整除时说明通过移动总是可以让高度差为0的。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve()
{
ll n,ans=0;
cin>>n;
for(int i=0;i<n;i++){
ll t;
cin>>t;
ans+=t;
}
if(ans%n)//不能整除
cout<<1<<endl;
else//可以整除
cout<<0<<endl;
}
int main()
{
ios::sync_with_stdio(false);
int t=1;
cin>>t;
while(t--) solve();
return 0;
}
题意:给定一个区间[l,r],为了使区间中所有的数字的按位与&
结果不为零,你需要去掉其中一部分数字。问:最少去掉多少数字使按位与结果不为零。
思路:2e5大概是2的18次方,也就是18位,每一位上1最多的那一组数字是最优的,其余数字需要去掉,即结果为区间长度-最优数字个数
。统计[1,2e5]区间所有数字每一位上的1个数的前缀和,方便查询。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+5;
ll a[20][N];
void solve()
{
ll l, r, ans = 0;
cin>>l>>r;
ll len = r - l + 1;
for(int i=0;i<20;i++){
ans=max(a[i][r]-a[i][l-1],ans);//统计每一位上1的个数的最优值
}
//区间长度-最优数字个数
cout<<len-ans<<endl;
}
int main()
{
int t;
cin>>t;
//每一位上1的个数的前缀和
for(int i=0;i<20;i++){
for(int j=1;j<N;j++){
a[i][j]=a[i][j-1]+((j>>i)&1);
}
}
while(t--) solve();
return 0;
}
题意:给定只包含’0’和’1’的两个串a和b,每次可以选中a串中的’1’并将a中的其它字符取反。问:至少需要多少次可以使a串变为b串?如果没有解输出-1.
大致思路:首先必须明晰:连续操作两次并选取不同下标的’1’相当于将不同位置的’0’和’1’互换。因此当a和b串中的’1’的个数相同时有解,或当选中a串中的一个’1’取反,此时,a串中的’1’的个数等于原来’0’的个数加1,也是有解的。否则无解。这样每两次操作可以还原两个值。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+5;
#define inf 0x3f3f3f3f
void solve()
{
int cnt=0,n;
string s,t;
cin>>n;
cin>>s>>t;
int cnt1=count(s.begin(),s.end(),'1');
int cnt2=count(t.begin(),t.end(),'1');
for(int i=0;i<n;i++) {
cnt+=(s[i]!=t[i]);
}
int res=inf;
if(cnt1==cnt2)
res=min(res,cnt);
if(cnt2==n-cnt1+1)//b串中的'1'的个数等于a串中的'0'的个数加1
res = min(res,n-cnt);
if(res==inf)
cout<<-1<<endl;
else
cout<<res<<endl;
}
int main()
{
int t;
cin>>t;
while(t--) solve();
return 0;
}