CF772
A#
题意:
给一个数组,每一次操作如下:
选两个位置上的数字和,把他们变成和,要求满足
进行任意多次操作后,整个数组的和最小是多少?
解答:
如果数组中的某个数字,在二进制下第位是,那么可以利用有限多次上述操作,让整个数组中只有该数字,二进制下这一位是,但是不能消掉。
所以答案是数组中所有数字,二进制下出现过的位数的和,具体来说对所有数字取或就可以。
#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#
题意:
给一个数组,每一次操作如下:
把一个位置上的数字改成到中的任意一个数字
请用最少的修改次数,使得数组中没有且的情况存在
解答:
从前往后考虑这个数组:
如果在某一个位置出现了并且的情况,而且前面都已经没有这种情况了。那么在这种情况下,显然修改是最好的办法。
因为改前两个数字只能消掉当前这个小凸起,而改后面的数字有可能把后面凸起也消掉。
不能改的太大,防止它本身又变成一个凸起,所以最好的方法是把改成这样它消掉了当前凸起,本身不会成为凸起,后一个凸起也有可能因此消掉。
#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#
题意:
给一个数组,每次操作如下:
选择三个位置,令
进行不超过次操作,让数组不下降
解答:
只要构造一个合法解就可以了。
那么从后往前考虑这个数组,假设当前位置是,那显然越小越好,不用管前面怎么样,因为能变多小,前面就能变多小,一定不下降。
最小的情况就是每个位置上的去减后面最大的数字,这个可以通过倒序遍历数组的时候一起得到,实现可以看代码。
如果变得最小还是不如前面小,那就寄了。
#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#
题意:
给定一些初始整数,它们在一个集合里面。
这个集合规定,如果在集合里,那么和也在集合里。
请问有多少小于的数字在这个集合里面?
解答:
首先,如果在集合里,那么和也在集合里的意思就是:
如果在集合里,那么二进制意义下,的末尾加一个和加两个代表的数字也在集合里。
不超过的数字就是说所有数字在二进制意义下不超过位
那么我们假设在二进制意义下有位
那么它带来的位数字就有,位数字有个,位数字有个,位数字有个,位数字有个。
这就是一个斐波那契的递推式!它带来的贡献就是,其中是斐波那契数列,这个前缀和可以预处理得到。
但是有重复的,比如和就会重复贡献,因为可以通过得到。
那我们就先把数字排序,然后对一个数字一直做逆操作
比如
如果这个过程中某个数字已经出现过了,那就说明这个数字被表示了,直接跳过这个数字。
#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#
题意:
数轴上有辆车,有个两辆车之间的关系:
关系一:无论车和速度是多少,二者都无法相遇
关系二:无论车和速度是多少,二者都会相遇
构造一种满足个关系的方案,或者输出无法满足。
解答:
关系一表示两者背道而驰,关系二表示二者相向而行。都表示车和方向相反。所以可以先二分图染色,如果无法染色成功就一定不行。
染色之后,要确定方案,假设黑色点是向左的,白色点是向右的,那么关系一表示,黑色点在白色点左边,关系二表示,黑色点在白色点的右边。
根据左右关系建立一个拓扑图,图上一条边表示在的左边,然后根据拓扑序确定每辆车的顺序。
#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#
题意:
数轴上给出个点的坐标和权值,一对点选择的代价是,每次询问给定,问在中选一对点的最小代价是多少?
解答:
首先,假设左边权值第一个小于等于的点是,右边第一个权值小于等于的点是,那么最终的答案一定是这对点中的某些点。
因为如果选择且,且那么去选择肯定更优。
这样问题转化成了,每次给定一个区间,选择一条被完全包含的代价最小的带权线段。就是扫描线裸题了。
#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;
}
/*
*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】