CF772

A#

题意:

给一个数组,每一次操作如下:

选两个位置上的数字aiaj,把他们变成xy,要求满足ai|aj=x|y

进行任意多次操作后,整个数组的和最小是多少?

解答:

如果数组中的某个数字,在二进制下第k位是1,那么可以利用有限多次上述操作,让整个数组中只有该数字,二进制下这一位是1,但是不能消掉。

所以答案是数组中所有数字,二进制下出现过的位数的和,具体来说对所有数字取或就可以。

Copy
#include<bits/stdc++.h> using namespace std; namespace red{ #define int long long #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define lowbit(i) ((i)&(-i)) #define mid ((l+r)>>1) #define eps (1e-8) const int N=3e5+10,mod=998244353,inf=2e9; int n,sum; int a[N]; inline void main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int T;cin>>T; while(T--) { cin>>n;sum=0; for(int i=1;i<=n;++i) { cin>>a[i]; sum|=a[i]; } cout<<sum<<'\n'; } } } signed main() { red::main(); return 0; } /* */

B#

题意:

给一个数组,每一次操作如下:

把一个位置上的数字改成1109中的任意一个数字

请用最少的修改次数,使得数组中没有ai>ai1ai>ai+1的情况存在

解答:

从前往后考虑这个数组:

如果在某一个位置出现了ai>ai1并且ai>ai+1的情况,而且前面都已经没有这种情况了。那么在这种情况下,显然修改ai+1是最好的办法。

因为改前两个数字只能消掉当前这个小凸起,而改后面的数字有可能把后面凸起也消掉。

ai+1不能改的太大,防止它本身又变成一个凸起,所以最好的方法是把ai+1改成max{ai,ai+2}这样它消掉了当前凸起,本身不会成为凸起,后一个凸起也有可能因此消掉。

Copy
#include<bits/stdc++.h> using namespace std; namespace red{ #define int long long #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define lowbit(i) ((i)&(-i)) #define mid ((l+r)>>1) #define eps (1e-8) const int N=3e5+10,mod=998244353,inf=2e9; int n,sum; int a[N]; inline void main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int T;cin>>T; while(T--) { cin>>n;sum=0; for(int i=1;i<=n;++i) cin>>a[i]; for(int i=2;i<n;++i) { if(a[i]>a[i-1]&&a[i]>a[i+1]) a[i+1]=max(a[i],a[i+2]),++sum; } cout<<sum<<'\n'; for(int i=1;i<=n;++i) cout<<a[i]<<" \n"[i==n]; } } } signed main() { red::main(); return 0; } /* */

C#

题意:

给一个数组,每次操作如下:

选择三个位置x<y<z,令ax=ayaz

进行不超过n次操作,让数组不下降

解答:

只要构造一个合法解就可以了。

那么从后往前考虑这个数组,假设当前位置是x,那显然x越小越好,不用管前面怎么样,因为x能变多小,前面就能变多小,一定不下降。

x最小的情况就是每个位置上的ay去减后面最大的数字,这个可以通过倒序遍历数组的时候一起得到,实现可以看代码。

如果x变得最小还是不如前面小,那就寄了。

Copy
#include<bits/stdc++.h> using namespace std; namespace red{ #define int long long #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define lowbit(i) ((i)&(-i)) #define mid ((l+r)>>1) #define eps (1e-8) const int N=3e5+10,mod=998244353,inf=2e9; int n,sum; int a[N],maxn,minn,tmp; int pos1,pos2; bool flag; struct node { int x,y,z; }st[N]; int top; inline void main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int T;cin>>T; while(T--) { cin>>n;sum=0;flag=1;top=0;pos1=pos2=n; for(int i=1;i<=n;++i) cin>>a[i]; maxn=minn=a[n];tmp=1e9+7; for(int i=n-1;i;--i) { if(a[i]>a[i+1]) { if(tmp>a[i+1]) { flag=0;break; } a[i]=tmp; st[++top]=(node){i,pos2,pos1}; ++sum; } if(a[i]-maxn<tmp) tmp=a[i]-maxn,pos2=i; if(a[i]>maxn) maxn=a[i],pos1=i; } if(!flag){cout<<"-1\n";continue;} else { cout<<sum<<'\n'; for(int i=1;i<=top;++i) cout<<st[i].x<<' '<<st[i].y<<' '<<st[i].z<<'\n'; } } } } signed main() { red::main(); return 0; } /* 1 5 -2 -1 -5 4 5 */

D#

题意:

给定一些初始整数,它们在一个集合里面。

这个集合规定,如果x在集合里,那么2x+14x也在集合里。

请问有多少小于2p的数字在这个集合里面?

解答:

首先,如果x在集合里,那么2x+14x也在集合里的意思就是:

如果x在集合里,那么二进制意义下,x的末尾加一个1和加两个0代表的数字也在集合里。

不超过2p的数字就是说所有数字在二进制意义下不超过p

那么我们假设x在二进制意义下有k

那么它带来的k+1位数字就有1k+2位数字有1个,k+3位数字有2个,k+4位数字有3个,k+5位数字有5个。

这就是一个斐波那契的递推式!它带来的贡献就是i=kpf[ik],其中f[i]是斐波那契数列,这个前缀和可以预处理得到。

但是有重复的,比如100111001就会重复贡献,因为10011可以通过1001得到。

那我们就先把数字排序,然后对一个数字一直做逆操作

比如10011>1001>100>1

如果这个过程中某个数字已经出现过了,那就说明这个数字被表示了,直接跳过这个数字。

Copy
#include<bits/stdc++.h> using namespace std; namespace red{ #define int long long #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define lowbit(i) ((i)&(-i)) #define mid ((l+r)>>1) #define eps (1e-8) const int N=3e5+10,mod=1e9+7,inf=2e9; int n,m,ans; int a[N]; int f[N],g[N]; map<int,int> q; inline void main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int T=1; f[0]=f[1]=1; g[0]=1; for(int i=2;i<=2e5;++i) f[i]=(f[i-1]+f[i-2])%mod; for(int i=1;i<=2e5;++i) g[i]=(g[i-1]+f[i])%mod; while(T--) { cin>>n>>m;ans=0; q.clear(); for(int i=1;i<=n;++i) cin>>a[i]; sort(a+1,a+n+1); for(int i=1;i<=n;++i) { int x=a[i]; int sum=0; while(x) ++sum,x>>=1; x=a[i]; bool flag=0; while(x) { if(q[x]){flag=1;break;} if(x%4==0) x>>=2; else if(x%2!=0) x>>=1; else break; } q[a[i]]=1; if(flag) continue; if(sum<=m) ans=(ans+g[m-sum])%mod; } cout<<ans<<'\n'; } } } signed main() { red::main(); return 0; } /* */

E#

题意:

数轴上有n辆车,有m个两辆车之间的关系:

关系一:无论车xy速度是多少,二者都无法相遇

关系二:无论车xy速度是多少,二者都会相遇

构造一种满足m个关系的方案,或者输出无法满足。

解答:

关系一表示两者背道而驰,关系二表示二者相向而行。都表示车xy方向相反。所以可以先二分图染色,如果无法染色成功就一定不行。

染色之后,要确定方案,假设黑色点是向左的,白色点是向右的,那么关系一表示,黑色点在白色点左边,关系二表示,黑色点在白色点的右边。

根据左右关系建立一个拓扑图,图上一条边x>y表示xy的左边,然后根据拓扑序确定每辆车的顺序。

Copy
#include<bits/stdc++.h> using namespace std; namespace red{ #define int long long #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define lowbit(i) ((i)&(-i)) #define mid ((l+r)>>1) #define eps (1e-8) const int N=3e5+10,mod=998244353,inf=2e9; int n,m; bool flag=1; vector<int> eg[N]; vector<int> g[N]; int col[N],rd[N]; queue<int> q; struct edge { int opt,x,y; }e[N]; int ans[N],idx; inline void dfs(int now,int c) { col[now]=c; for(auto t:eg[now]) { if(col[t]) { if(col[t]==col[now]) flag=0; continue; } dfs(t,c^1); } } inline void main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); cin>>n>>m; for(int i=1;i<=m;++i) { int opt,x,y;cin>>opt>>x>>y; e[i]=(edge){opt,x,y}; eg[x].push_back(y); eg[y].push_back(x); } for(int i=1;i<=n;++i) { if(!col[i]) dfs(i,2); } for(int i=1;i<=m;++i) { if(col[e[i].x]==3) swap(e[i].x,e[i].y); if(e[i].opt==1) g[e[i].x].push_back(e[i].y),++rd[e[i].y]; else g[e[i].y].push_back(e[i].x),++rd[e[i].x]; } for(int i=1;i<=n;++i) if(!rd[i]) q.push(i); while(!q.empty()) { int now=q.front(); q.pop(); ans[now]=++idx; for(int t:g[now]) { --rd[t]; if(!rd[t]) q.push(t); } } for(int i=1;i<=n;++i) if(!ans[i]) flag=0; if(!flag) cout<<"NO\n"; else { cout<<"YES\n"; for(int i=1;i<=n;++i) { if(col[i]==2) cout<<"L "; else cout<<"R "; cout<<ans[i]<<'\n'; } } } } signed main() { red::main(); return 0; } /* */

F#

题意:

数轴上给出n个点的坐标xi和权值wi,一对点选择的代价是|xixj|(wi+wj),每次询问给定[l,r],问在l,r中选一对点的最小代价是多少?

解答:

首先,假设i左边权值第一个小于等于wi的点是Li,右边第一个权值小于等于wi的点是Ri,那么最终的答案一定是(Li,i),(i,Ri)2n对点中的某些点。

因为如果选择(x,i)wx<=wi,且xLi那么去选择(x,Li)肯定更优。

这样问题转化成了,每次给定一个区间[l,r],选择一条被[l,r]完全包含的代价最小的带权线段。就是扫描线裸题了。

Copy
#include<bits/stdc++.h> using namespace std; namespace red{ #define int long long #define ls(p) (p<<1) #define rs(p) (p<<1|1) #define lowbit(i) ((i)&(-i)) #define mid ((l+r)>>1) #define eps (1e-8) const int N=3e5+10,mod=998244353,inf=2e9; int n,m; int a[N],w[N]; int tl[N],tr[N],st[N],top; int ret[N]; struct node { int l,r,id; inline bool operator < (const node &t) const { return r<t.r; } }q[N]; vector<node> v[N]; struct segment_tree { int ans[N<<2]; inline void init() { memset(ans,0x3f,sizeof(ans)); } inline void update(int pos,int l,int r,int p,int k) { ans[p]=min(ans[p],k); if(l==r) return; if(pos<=mid) update(pos,l,mid,ls(p),k); else update(pos,mid+1,r,rs(p),k); } inline int query(int tl,int tr,int l,int r,int p) { if(tl<=l&&r<=tr) return ans[p]; int ret=2e18; if(tl<=mid) ret=min(ret,query(tl,tr,l,mid,ls(p))); if(tr>mid) ret=min(ret,query(tl,tr,mid+1,r,rs(p))); return ret; } }T; inline void main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int qaq=1; while(qaq--) { cin>>n>>m; for(int i=1;i<=n;++i) { cin>>a[i]>>w[i]; while(top&&w[st[top]]>=w[i]) { tr[st[top--]]=i; } st[++top]=i; } while(top) tr[st[top--]]=n; for(int i=n;i;--i) { while(top&&w[st[top]]>=w[i]) { tl[st[top--]]=i; } st[++top]=i; } while(top) tl[st[top--]]=1; for(int i=1;i<=n;++i) { if(i-tl[i]>0) v[i].push_back((node){tl[i],(a[i]-a[tl[i]])*(w[i]+w[tl[i]])}); if(tr[i]-i>0) v[tr[i]].push_back((node){i,(a[tr[i]]-a[i])*(w[i]+w[tr[i]])}); } for(int i=1;i<=m;++i) { cin>>q[i].l>>q[i].r; q[i].id=i; } sort(q+1,q+m+1); T.init(); int now=1; for(int i=1;i<=n;++i) { for(auto t:v[i]) { T.update(t.l,1,n,1,t.r); } while(now<=m&&q[now].r<=i) { ret[q[now].id]=T.query(q[now].l,q[now].r,1,n,1); ++now; } } for(int i=1;i<=m;++i) cout<<ret[i]<<'\n'; } } } signed main() { red::main(); return 0; } /* */
posted @   lovelyred  阅读(59)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示
CONTENTS