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>>a[i][j];

}

}

/*

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&&a[i][j]==1)num1.set((i-1));

if(j==2&&a[i][j]==1)num2.set((i-1));

if(j==3&&a[i][j]==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意义下每个数出现的位置存一下;

比如 pos[1] 里面存的就是 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>>a[i];

Max[i]=getmax(a[i]);

}

int ans=0;

fr(D,1,9){

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

pos[0].pb(0LL);

int lst1=0;

int lst2=-1;

int cur=0;

fr(i,1,n){

cur=(cur+(a[i-1]%D))%D;

if(Max[i-1]>D){

lst1=i;

lst2=-1;

}

else if(Max[i-1]==D){

lst2=i;

}

if(lst2!=-1){

int L=lst1;

int R=lst2-1;

//auto v=pos[cur];

const auto& v=pos[cur];

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

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

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

}

pos[cur].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&&ta[idxa].x0<tb[idxb].y0){

cur=max(cur,ta[idxa].y0);

idxa++;

}

if(cur<=tb[idxb].x0){

res++;

cur=max(cur,tb[idxb].y0);

}

idxb++;

}

int ans=res+sza;

cans;

}

signed main(){

GG;

int _t=1;

//cin>>_t;

while(_t--){

solve();

}

}

相关推荐
CylMK3 小时前
题解:P11625 [迷宫寻路 Round 3] 迷宫寻路大赛
c++·数学·算法
计算机安禾3 小时前
【数据结构与算法】第44篇:堆(Heap)的实现
c语言·开发语言·数据结构·c++·算法·排序算法·图论
kaikaile19953 小时前
能量算子的MATLAB实现与详细算法
人工智能·算法·matlab
tankeven3 小时前
HJ175 小红的整数配对
c++·算法
Aaron15883 小时前
数字波束合成DBF与模拟波束合成ABF对比浅析
大数据·人工智能·算法·硬件架构·硬件工程·信息与通信·信号处理
成都易yisdong3 小时前
实现三北方向转换计算器(集成 WMM2025 地磁模型)
开发语言·windows·算法·c#·visual studio
汀、人工智能3 小时前
[特殊字符] 第91课:课程表
数据结构·算法·数据库架构·图论·bfs·课程表
wfbcg3 小时前
每日算法练习:LeetCode 36. 有效的数独 ✅
算法·leetcode·职场和发展
智者知已应修善业4 小时前
【51单片机非精准计时2个外部中断启停】2023-5-29
c++·经验分享·笔记·算法·51单片机