cf1849做题记录
A
分类讨论 和 的大小即可。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
void solve(){
int a,b,c;
read(a),read(b),read(c);
if(b+c<a){
write_endl((b+c)*2+1);
}
else{
write_endl(a*2-1);
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t;
read(t);
while(t--){
solve();
}
return 0;
}
B
可以发现因为每次选的是血最多的,所以影响实际死亡顺序的是最后一击前的血量。以血量模 的余数为第一关键字(如果血量模 的余数为 则看作余数为 ),以编号为第二关键字排序即可。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=3e5+10;
int n,k;
struct node{
int id,val;
}a[N];
bool cmp(node x,node y){
return x.val==y.val?x.id<y.id:x.val>y.val;
}
void solve(){
read(n),read(k);
for(int i=1;i<=n;i++){
read(a[i].val);
a[i].val=(a[i].val-1)%k+1;
a[i].id=i;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++){
write_space(a[i].id);
}
putchar('\n');
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t;
read(t);
while(t--){
solve();
}
return 0;
}
C
每次排序时的前缀 和后缀 都是没有意义的,该在最前面的还在最前面,该在最后面的还在最后面。所以维护两个数组 表示 中第一个 的位置, 表示 中最后一个 的位置,每次排序会修改的部分只有 这个部分。注意的是当 时,整个序列没有修改,将修改操作变为 即可。答案为不同的操作数量,用 map
计数一下就行。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=2e5+10;
int nxt[N],pre[N],n,m;
char s[N];
void solve(){
read(n),read(m);
for(int i=1;i<=n;i++){
s[i]=getchar();
while(s[i]!='0'&&s[i]!='1'){
s[i]=getchar();
}
}
for(int i=1;i<=n;i++){
if(s[i]=='0'){
pre[i]=i;
}
else{
pre[i]=pre[i-1];
}
}
nxt[n+1]=n+1;
for(int i=n;i;i--){
if(s[i]=='1'){
nxt[i]=i;
}
else{
nxt[i]=nxt[i+1];
}
}
map<pii,int>vis;
for(int i=1;i<=m;i++){
int l,r;
read(l),read(r);
if(nxt[l]>pre[r]){
vis[mp(0,0)]=1;
}
else{
vis[mp(nxt[l],pre[r])]=1;
}
}
write_endl(vis.size());
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t;
read(t);
while(t--){
solve();
}
return 0;
}
D
对于一个非零段,如果从左端开始,则可以将该非零段的右边第一个 的位置染色,从右端开始则可以将左边第一个 的位置染色。如果有 ,可以从 的位置开始,将左右的第一个 都染色。所以我们先将有 的非零段和其左右的第一个 染色。剩下的 直接贪心染色。对于从左往右的每个非零段,如果左侧的第一个 未染色,则将其染色,否则将右侧的第一个 染色,最后剩下的 单独染一次色即可。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=2e5+10;
int n,a[N],b[N];
void solve(){
int ans=0;
read(n);
for(int i=1;i<=n;i++){
read(a[i]);
}
for(int i=1,j;i<=n;i=j+1){
int flag=0;
for(j=i;j<=n;j++){
if(!a[j]){
break;
}
flag=max(flag,a[j]);
}
if(flag==2){
ans++;
for(int k=i-1;k<=j;k++){
b[k]=1;
}
}
}
for(int i=1,j;i<=n;i=j+1){
int flag=0;
for(j=i;j<=n;j++){
if(!a[j]){
break;
}
flag=max(flag,a[j]);
}
if(flag==1){
ans++;
if(i>1&&!b[i-1]){
for(int k=i-1;k<j;k++){
b[k]=1;
}
}
else{
for(int k=i;k<=j;k++){
b[k]=1;
}
}
}
}
for(int i=1;i<=n;i++){
if(!b[i]){
ans++;
}
}
write_endl(ans);
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}
E
在确定右端点 的情况下,可能合法的区间有 个,令 表示左端点为 时区间的合法性。如果此时我们在后面加上一个 ,可能影响区间的情况只有 为新区间的最大值和区间最小值。 是区间最大值会使区间变得合法,是区间最小值会使区间变得不合法。
可以预处理出 中最后一个大于 的数的位置 和最后一个小于 的数的位置 ,如果不存在大于或不存在小于的数则为 。如果 大于 则 会在左端点在一段区间中时最小值,将 赋值为 ,反之则为最大值,将 赋值为 。用线段树维护 数组的权值,只需要实现区间赋 ,求所有权值和的操作。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define int long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=1e6+10;
int n,a[N],pre_mn[N],pre_mx[N],stk[N],top;
namespace Seg_Tree{
int ans[N<<2],tag[N<<2];
int ls(int p){
return p<<1;
}
int rs(int p){
return p<<1|1;
}
void f(int p,int l,int r,int val){
tag[p]=val+1;
ans[p]=(r-l+1)*val;
}
void push_down(int p,int l,int r){
if(tag[p]){
int mid=(l+r)>>1;
f(ls(p),l,mid,tag[p]-1);
f(rs(p),mid+1,r,tag[p]-1);
}
}
void push_up(int p){
ans[p]=ans[ls(p)]+ans[rs(p)];
}
void update(int p,int l,int r,int q_l,int q_r,int val){
if(q_l<=l&&r<=q_r){
f(p,l,r,val);
return;
}
int mid=(l+r)>>1;
push_down(p,l,r);
if(q_l<=mid){
update(ls(p),l,mid,q_l,q_r,val);
}
if(q_r>mid){
update(rs(p),mid+1,r,q_l,q_r,val);
}
push_up(p);
}
}
void solve(){
read(n);
for(int i=1;i<=n;i++){
read(a[i]);
}
for(int i=1;i<=n;i++){
while(top&&a[stk[top]]>a[i]){
top--;
}
pre_mn[i]=stk[top];
stk[++top]=i;
}
top=0;
for(int i=1;i<=n;i++){
while(top&&a[stk[top]]<a[i]){
top--;
}
pre_mx[i]=stk[top];
stk[++top]=i;
}
int ans=0;
for(int i=2;i<=n;i++){
if(a[i-1]<a[i]){
Seg_Tree::update(1,1,n,pre_mx[i]+1,i-1,1);
}
else{
Seg_Tree::update(1,1,n,pre_mn[i]+1,i-1,0);
}
ans+=Seg_Tree::ans[1];
}
write_endl(ans);
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}
F
对于这种划分到两个集合的题要能够惯性想到二分图上去,想到二分图上后就好做了。
这里有两种做法解决本题。
第一种做法,二分答案,只连接异或和小于二分的权值 的边,判断是否为二分图即可,如果为二分图,则说明所有异或和小于 的数对都不同时在一个集合中,答案肯定大于等于 。但这里有个问题,在 较大时,连的边是接近 的此时我们一次染色判断二分图复杂度太大,需要考虑优化建图。
有一个结论是,对于一个排好序的数组 ,如果存在一个 使得 ,此时一定是无解。
证明:令 , 的最高位为 ,必然的是 第 位为 , 的第 位为 。根据鸽巢原理, 这 个数在第 位上至少有三个数相同,也就意味着至少会有三个数两两异或和小于 ,必然不是二分图,同理 , 等也是一样的。
这个结论让我们的边数从原来的 级别变成了与 同阶。如果无解,那么加上更多边一定无解;如果有解,那么问题就变成了是否会存在 且不加该边时原图为二分图的情况,答案为不能。回到开始的分类讨论,假定 第 位均为 ,那么在 连边时会连出奇环,假定 第 位为 ,那么在 连边时会连出奇环,所以上述问题所说的情况一定不存在。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=2e5+10;
int n,a[N],col[N],val[N],pos[N],flag=0;
vector<pii>id;
vector<int>e[N];
void dfs(int u,int color){
col[u]=color;
for(auto v:e[u]){
if(!col[v]){
dfs(v,3-color);
}
if(col[v]!=3-color){
flag=0;
return;
}
}
}
bool check(int x){
for(int i=1;i<=n;i++){
e[i].clear();
col[i]=0;
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=min(i+3,n);j++){
if((val[i]^val[j])<x){
e[i].pb(j);
e[j].pb(i);
}
}
}
flag=1;
for(int i=1;i<=n;i++){
if(!col[i]){
dfs(i,1);
}
}
return flag;
}
void solve(){
read(n);
for(int i=1;i<=n;i++){
read(a[i]);
id.pb(mp(a[i],i));
}
sort(id.begin(),id.end());
for(int i=1;i<=n;i++){
pos[id[i-1].second]=i;
val[i]=id[i-1].first;
}
if(n==2){
puts("10");
return;
}
int l=1,r=(1<<30)-1,ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)){
ans=mid;
l=mid+1;
}
else{
r=mid-1;
}
}
check(ans);
for(int i=1;i<=n;i++){
write(col[pos[i]]-1);
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}
第二种做法,每次选出最小的边,要答案最大,这条边的两个端点显然应该属于不同集合。我们一直加边,直到加边后图不再是二分图。但其实没必要是图,一棵树就已经能够把哪个点属于哪个集合定下来了,根据这个思路,我们只需求出完全图的最小异或生成树,对其进行黑白染色,就是最后的划分结果。求完全图图的最小异或生成树类似于CF888G,感兴趣的可以直接看01trie,这里就不给出代码了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?