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();

}

}

相关推荐
小哈里1 小时前
【知识】从学科到实践:自然・工程・社科・人文|算法・研发・产品・品牌设计
程序人生·算法·产品·设计·工程
小π军2 小时前
最大重叠区间数量
数据结构·算法
镜像视界(浙江)科技有限公司2 小时前
《视频孪生之上:二维展示终结,三维空间计算重构城市逻辑》——跨摄像连续表达 × 三角测量厘米级定位 × 动态轨迹建模,构建新一代城市空间
大数据·人工智能·算法·矩阵·音视频·空间计算
a187927218312 小时前
【算法】双指针与滑动窗口(二):滑动窗口——吃进、判定、吐出
算法·leetcode·双指针·滑动窗口·原理·模板·算法讲解
铭哥的编程日记2 小时前
从一道 LeetCode Hard 到吃透一类题:加权区间调度「排序 + 二分 + DP」
算法·leetcode·职场和发展
Navigator_Z3 小时前
LeetCode //C - 1248. Count Number of Nice Subarrays
c语言·算法·leetcode
wzdark4 小时前
多维数组在算法设计中的存储映射问题4
算法
Phil3234 小时前
多智能体不是越多越好:Google《Towards a Science of Scaling Agent Systems》论文深度解读
算法
6Hzlia4 小时前
【Classic 150 刷题计划】 LeetCode 26. 删除有序数组中的重复项 | C++ 快慢双指针经典模板
c++·算法·leetcode
huang5791475 小时前
基于滑动窗口的流式数据算法优化思路3
算法