AT-abc347(C-E)
AtCoder Beginner Contest 347
C - Ideal Holidays
这场做得最头疼的题
分析
容易想到先用(di+a+b-1)%(a+b)+1把di映射到[1,a+b]的区间再排序,但由于未知星期一是哪天,我们也无法确定映射后的di是星期几
关于这个映射可以自己推一下
我们取a+b=7看几个例子
对于
3 2 5
1 2 9
经映射后得
1 2 2
取第一天是星期一,所有di都在[1,2]内
而对于
4 2 5
1 2 7 9
经映射再排序后得
1 2 2 7
这时取第一天为星期一,d[4]为星期日,取第七天为星期一,第二天为星期三,我们发现此时不能使所有di都在[1,2]内
但若是b=4,a=3
4 3 4
1 2 7 9
经映射再排序后得
1 2 2 7
此时取第七天为星期一,第二天为星期三,我们发现此时能使所有di都在[1,3]内
而
4 3 4
1 2 6 9
显然又无法实现
所以能得到:映射再排序后存在d[i]-d[i-1]>b就能够实现,但若是所有d[i]原本就在[1,a]的范围内呢,要处理这种情况,我们可以使d[n+1]=d[0]+a+b,或者做一个特判
代码
void solve(){
int n,a,b,x;cin>>n>>a>>b;
vector<int>d;
rep(i,1,n){
cin>>x;
d.push_back((x+a+b-1)%(a+b)+1);//映射处理
}
sort(d.begin(),d.end());
d.push_back(d[0]+a+b);//相当于加上边界,处理一周七天时1 2 9的情况
rep(i,1,d.size()-1){
if(d[i]-d[i-1]>b){
cout<<"Yes";
return;
}
}
cout<<"No";
}
D - Popcount and XOR
贪心
分析
我们知道只有两数在二进制形式下当前位不同时,异或后的当前位才为1,反推过来,对于x^y=c ,c的二进制下当前位为1的话说明x或y的当前位一定是一1一0,而又由于要保证a与b个1都要刚好用尽,因此我们的贪心策略就是,对于c的二进制下为1的位,若a>b,则用a,此时x加上当前位的贡献,反之用b,y加上当前位的贡献,这样以后再判断是否满足ab相等且大于等于0
代码
void solve(){
int a,b,x=0,y=0,c;cin>>a>>b>>c;
rep(i,0,60){
if(c>>i&1){
if(a>b){
x+=(1ll<<i);//赛时甚至是用的快速幂(っ °Д °;)っ
a--;
}
else{
y+=(1ll<<i);
b--;
}
}
}
if(a!=b||a<0||b<0){
cout<<"-1";
return;
}
rep(i,0,60){
if(!(c>>i&1)&&a){
x+=(1ll<<i);
y+=(1ll<<i);
a--;
}
}
if(a){//还要特判a或者b是否有剩
cout<<"-1";
return;
}
cout<<x<<" "<<y;
}
E - Set Add Query
分析
先贴一个会t的纯模拟做法是为了更好地理解题意
void solve(){
int n,q,x;cin>>n>>q;
set<int>s;
rep(i,1,q){
cin>>x;
if(!s.count(x)){
s.insert(x);
}
else s.erase(x);
for(auto it:s){
if(it<=n) a[it]+=s.size();
}
}
rep(i,1,n) cout<<a[i]<<" ";
}
我们思考如何优化这个O(n*n)的做法——也就是不需要每次更新set时遍历更新a[i]。
很显然对于元素x,只有在它被插入set期间时才对答案有这期间s.size()和的贡献,而s.size()的和可以用前缀和p[i]做预处理,于是我们可以记录x在set里存在的下标,在循环外对于1~n的每个i成对地遍历它的下标l,r,答案a[i]=p[r-1]-p[l-1](遍历到r对应的下标时x已经被弹出set,对答案无贡献)
同时注意这些下标不一定成对,也就是有些数最后还存在于set里,对于这些数,它们最后一次加入集合的下标为l,此后对答案的贡献为最终的s.size()-p[l-1],而这个s.size()又等于p[q],所以我们可以给这些数的下标数组加上q+1,使得对于最后的l,也有成对的r=p[q]
对于4 6
1 2 3 2 4 2
每个x对应的s.size()为
1 2 3 2 3 2
前缀和为
1 3 6 8 11 13
则对于2这个数,它的下标为{2,4,6}
ans=p[4-1]-p[2-1]+p[7-1]-p[6-1]=8-1+13-13=7
代码
const int N=2e5+5;
int p[N],a[N];
vector<int>v[N];
void solve(){
int n,q,x;cin>>n>>q;
set<int>s;
//vector<vector<int>>v;会re
rep(i,1,q){
cin>>x;
if(!s.count(x)){
s.insert(x);
}
else s.erase(x);
if(x<=n) v[x].push_back(i);//记录加入/弹出set时的下标
p[i]=p[i-1]+s.size();//前缀和处理
}
for(auto i:s){//最后还存在set里的数
if(i<=n) v[i].push_back(q+1);
}
rep(i,1,n){
int sz=v[i].size();
for(int j=0;j<sz;j+=2){//成对遍历下标
int l=v[i][j],r=v[i][j+1];
a[i]+=p[r-1]-p[l-1];
}
cout<<a[i]<<" ";
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】