The 6th Liaoning Provincial Collegiate Programming Contest - External 复盘

AC:7

D:

#include<bits/stdc++.h>

#define int long long

#define inf 0x3f3f3f3f3f3f3f

#define GG ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

#define cnot cout<<"NO"<<"\n"

#define cyes cout<<"YES"<<"\n"

#define cans cout<<ans<<"\n"

#define pb push_back

#define x0 first

#define y0 second

#define lc p<<1

#define rc p<<1|1

#define mem(a,b) memset(a,b,sizeof(a))

#define sp(x) fixed<<setprecision(x)

#define all(v) v.begin(),v.end()

#define fr(i,st,ed) for(int i=st;i<=ed;i++)

#define ffr(i,st,ed,dt) for(int i=st;i<=ed;i+=dt)

using namespace std;

typedef pair<int,string>Pis;

typedef pair<int,int>Pii;

typedef pair<string,string>Pss;

const int N=2e4+10,mod=1e9+7,M=1e6+10;

int lowbit(int x){

return x&(-x);}

void solve(){

int n;

cin>>n;

vector<vector<int>>a(n+1,vector<int>(4));

fr(i,1,n){

fr(j,1,3){

cin>>aij;

}

}

/*

int num1=0;

int num2=0;

int num3=0;

*/

bitset<105>num1,num2,num3,Ans;

fr(i,1,n){

fr(j,1,3){

if(j==1&&aij==1)num1.set((i-1));

if(j==2&&aij==1)num2.set((i-1));

if(j==3&&aij==1)num3.set((i-1));

Ans.set((i-1));

}

}

/*

cout<<(num1|num2)<<endl<<(num2|num3)<<endl<<(num1|num3)<<endl;

cout<<(1<<n)-1<<endl;

*/

if(num1==Ans||num2==Ans||num3==Ans)cout<<1<<"\n";

else if(((num1|num2)==Ans)||((num1|num3)==Ans)||((num2|num3)==Ans))cout<<2<<"\n";

else cout<<3<<"\n";

}

signed main(){

GG;

int _t=1;

//cin>>_t;

while(_t--){

solve();

}

}

E:

因为最大数字只可能是1-9,很容易想到尝试枚举出现的最大数字;

接下来考虑对于每一个最大数字,如何找到每一段区间;

我们1-n扫描整个数组,对于每个i,我们希望统计以i为右端点的数组个数,所以我们需要确定此时左端点的合法区间

对于左端点存在的区间,显然,如果上一个数>D(此时枚举的最大数字),那么左区间应该被更新为i,同时右区间应该被设为不存在,如果上一个数==D,那么右区间应该被更新为i-1,直到下一个等于D的数出现;

解释一下这么寻找的理由:对于每一个右端点,我们希望它向前寻找左端点构成的区间里面含有一个D,同时不含>D的数,那我至少需要找到上一个D存在的位置,同时这段区间不能有>D的数,至多找到上一个>D出现的位置后一位;

画个图帮助理解:

现在考虑如何在这段区间找左端点使得区间和整除于D;

我们知道,在mod m意义下的前缀和相同等价这两个前缀和直接的区间和%m==0;

所以,将mod m意义下每个数出现的位置存一下;

比如 pos1 里面存的就是 mod m意义下为1的数的位置;

而现在我们知道了L,R;

等价于在一个数组里面求两个数之间有多少数

这是一个经典二分求点距离的问题;

至此这道题的思路就完成了,具体实现看code:

#include<bits/stdc++.h>

#define int long long

#define inf 0x3f3f3f3f3f3f3f

#define GG ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

#define cnot cout<<"NO"<<"\n"

#define cyes cout<<"YES"<<"\n"

#define cans cout<<ans<<"\n"

#define pb push_back

#define x0 first

#define y0 second

#define lc p<<1

#define rc p<<1|1

#define mem(a,b) memset(a,b,sizeof(a))

#define sp(x) fixed<<setprecision(x)

#define all(v) v.begin(),v.end()

#define fr(i,st,ed) for(int i=st;i<=ed;i++)

#define ffr(i,st,ed,dt) for(int i=st;i<=ed;i+=dt)

using namespace std;

typedef pair<int,string>Pis;

typedef pair<int,int>Pii;

typedef pair<string,string>Pss;

const int N=2e4+10,mod=1e9+7,M=1e6+10;

int lowbit(int x){

return x&(-x);}

int getmax(int x){

int res=0;

while(x>0){

int num=x%10;

res=max(res,num);

x/=10;

}

return res;

}

vector<int>Cnt(10);

void solve(){

int n;

cin>>n;

vector<int>a(n+1),Max(n+1);

fr(i,0,n-1){

cin>>ai;

Maxi=getmax(ai);

}

int ans=0;

fr(D,1,9){

vector<vector<int>>pos(D);

pos0.pb(0LL);

int lst1=0;

int lst2=-1;

int cur=0;

fr(i,1,n){

cur=(cur+(ai-1%D))%D;

if(Maxi-1>D){

lst1=i;

lst2=-1;

}

else if(Maxi-1==D){

lst2=i;

}

if(lst2!=-1){

int L=lst1;

int R=lst2-1;

//auto v=poscur;

const auto& v=poscur;

auto it1=lower_bound(all(v),L);

auto it2=upper_bound(all(v),R);

ans+=(int)distance(it1,it2);

}

poscur.pb(i);

}

}

cans;

}

signed main(){

GG;

int _t=1;

cin>>_t;

while(_t--){

solve();

}

}

M

我们可以把比赛分成两种,a>=b a<b;

对于第一种比赛,我们把a从小到大排,不难发现,只要顺次完成他们,他们一定都可以被进行,因为完成比赛的提升比要求小,而下一场的要求总是高于这一场的要求;

所以我们的目标应该是:在确保所有第一种比赛可以完成的情况下,尽可能多的完成第二种比赛;

我们考虑第二种比赛对第一种比赛的影响,很显然是能力提升到b,那么我们只要把需求值小于b的所有比赛打完,这次比赛的结果就不会对第一组产生影响,这时我们只要判断此时的能力能否参加这场比赛,能参加就参加,不能则跳过看下一个;

所以对第二种比赛排序的第一关键字是b;

这个贪心的合理性在于,第一种比赛能否全部打完是稳定可控的,为了顺利打完第一组比赛,对于每个第二组中的比赛来说至多是放弃一场,而打第二组比赛的影响是不可控的,因此减少的比赛场数只可能更多;

实现见code:

#include<bits/stdc++.h>

#define int long long

#define inf 0x3f3f3f3f3f3f3f

#define GG ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

#define cnot cout<<"NO"<<"\n"

#define cyes cout<<"YES"<<"\n"

#define cans cout<<ans<<"\n"

#define pb push_back

#define x0 first

#define y0 second

#define lc p<<1

#define rc p<<1|1

#define mem(a,b) memset(a,b,sizeof(a))

#define sp(x) fixed<<setprecision(x)

#define all(v) v.begin(),v.end()

#define fr(i,st,ed) for(int i=st;i<=ed;i++)

#define ffr(i,st,ed,dt) for(int i=st;i<=ed;i+=dt)

using namespace std;

typedef pair<int,string>Pis;

typedef pair<int,int>Pii;

typedef pair<string,string>Pss;

const int N=2e4+10,mod=1e9+7,M=1e6+10;

int lowbit(int x){

return x&(-x);}

bool cmp1(Pii a,Pii b){//a

return a.x0==b.x0?a.y0>b.y0:a.x0<b.x0;

}

bool cmp2(Pii a,Pii b){//b

return a.y0==b.y0?a.x0<b.x0:a.y0<b.y0;

}

void solve(){

int n;

cin>>n;

vector<Pii>ta,tb;

//ta:a>=b

//tb:a<b

int x,y;

fr(i,1,n){

cin>>x>>y;

if(x>=y){

ta.pb({x,y});

}

else{

tb.pb({x,y});

}

}

int res=0;

sort(all(ta),cmp1);

sort(all(tb),cmp2);

int sza=ta.size();

int szb=tb.size();

int idxa=0;

int idxb=0;

int cur=0;

while(idxb<szb){

while(idxa<sza&&idxb<szb&&taidxa.x0<tbidxb.y0){

cur=max(cur,taidxa.y0);

idxa++;

}

if(cur<=tbidxb.x0){

res++;

cur=max(cur,tbidxb.y0);

}

idxb++;

}

int ans=res+sza;

cans;

}

signed main(){

GG;

int _t=1;

//cin>>_t;

while(_t--){

solve();

}

}

相关推荐
JieE2121 天前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
Jack201 天前
HarmonyOS开发中错误处理策略:网络异常统一处理
算法
小小杨树2 天前
读懂色彩:拍照调色不再难
算法·计算机视觉·配色
JieE2122 天前
LeetCode 226. 翻转二叉树|JS 递归超详细拆解,二叉树入门经典题
javascript·算法
JieE2122 天前
LeetCode 104. 二叉树的最大深度|递归思路超详细拆解
javascript·算法
vivo互联网技术2 天前
CVPR 2026 | 全新强化学习框架 BeautyGRPO:重塑真实人像
算法·大模型·cvpr·影像
Darling噜啦啦2 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
用户497863050733 天前
(一)小红的数组操作
算法·编程语言
怕浪猫3 天前
Electron 系列文章封面图
算法·架构·前端框架