首页 > 其他分享 >NFLS 241014 比赛总结

NFLS 241014 比赛总结

时间:2024-10-14 23:34:00浏览次数:6  
标签:const 比赛 int res LL NFLS 区间 MAXN 241014

T1 JZOI5246 Trip

Problem

有一串长为 \(n\) 的序列 \(a\),有 \(m\) 组询问,每组询问给出一个区间,求区间内有多少个数满足以下条件之一

  • 在区间内,它的左侧不存在大于它的数。
  • 在区间内,它的右侧不存在大于它的数。

Solution

离散化,用权值线段树求出序列上每个数左边和右边第一个比它大的数的位置,记为 \(L,R\)。

因此对于每组询问 \([l,r]\),我们要求 \([l,r]\) 中所有 \(L<l\) 或 \(r<R\) 的点,可以大减小来求:我们先求出序列中所有 \(L<l\) 或 \(r<R\) 的点,减去这之中不在 \([l,r]\) 中的点。而我们发现不在区间中的点一定都是满足 \(L<l\) 或 \(r<R\) 的,因此直接减去 \(n-(r-l+1)\) 。

现在问题转化为一个二维数点:\(n\) 个点 \((L,R)\),\(m\) 组询问 \(l,r\),求 \(L<l\) 或 \(r<R\) 的点,树状数组做即可。代码中是先求的 1 号部分,然后统一求的 2 3 号部分,避免为了 3 号部分又重新倒着做一遍。

代码
#include<bits/stdc++.h>
#define lch (pos<<1)
#define rch (pos<<1|1)
#define getmid int mid=(l+r)/2
using namespace std;
#ifdef ONLINE_JUDGE
#define getchar __getchar
inline char __getchar(){
    static char ch[1<<20],*l,*r;
    return (l==r&&(r=(l=ch)+fread(ch,1,1<<20,stdin),l==r))?EOF:*l++;
}
#endif
template<class T>inline void rd(T &x){
    T res=0,f=1;
    char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while('0'<=ch && ch<='9'){res=res*10+ch-'0';ch=getchar();}
    x=res*f;
}
template<class T>inline void wt(T x,char endch='\0'){
    static char wtbuff[20];
    static int wtptr;
    if(x==0){
        putchar('0');
    }
    else{
        if(x<0){x=-x;putchar('-');}
        wtptr=0;
        while(x){wtbuff[wtptr++]=x%10+'0';x/=10;}
        while(wtptr--) putchar(wtbuff[wtptr]);
    }
    if(endch!='\0') putchar(endch);
}
typedef pair<int,int> pii;
const int MAXN=1e6+5;
int n,m,a[MAXN],na[MAXN],buck[MAXN],len,ans[MAXN];
pii rg[MAXN];
struct NQRY{
    int first,second,id;
    bool operator < (const NQRY y){
        return first<y.first;
    }
}qry[MAXN];
class SegTreeMax{
private:
    int t[MAXN<<2];
    inline void pushup(int pos){
        t[pos]=max(t[lch],t[rch]);
    }
public:
    void update(int pos,int l,int r,int aim,int val){
        if(l==r){
            t[pos]=val;
            return;
        }
        getmid;
        if(aim<=mid) update(lch,l,mid,aim,val);
        else update(rch,mid+1,r,aim,val);
        pushup(pos);
    }
    int query(int pos,int l,int r,int ll,int rr){
        if(ll>rr) return 0;
        if(ll<=l && r<=rr){
            return t[pos];
        }
        getmid,res=0;
        if(ll<=mid) res=max(res,query(lch,l,mid,ll,rr));
        if(mid<rr) res=max(res,query(rch,mid+1,r,ll,rr));
        return res;
    }
}stmax;
class SegTreeMin{
private:
    int t[MAXN<<2];
    inline void pushup(int pos){
        t[pos]=min(t[lch],t[rch]);
    }
public:
    SegTreeMin(){
        memset(t,0x3f,sizeof(t));
    }
    void update(int pos,int l,int r,int aim,int val){
        if(l==r){
            t[pos]=val;
            return;
        }
        getmid;
        if(aim<=mid) update(lch,l,mid,aim,val);
        else update(rch,mid+1,r,aim,val);
        pushup(pos);
    }
    int query(int pos,int l,int r,int ll,int rr){
        if(ll>rr) return 0x3f3f3f3f;
        if(ll<=l && r<=rr){
            return t[pos];
        }
        getmid,res=0x3f3f3f3f;
        if(ll<=mid) res=min(res,query(lch,l,mid,ll,rr));
        if(mid<rr) res=min(res,query(rch,mid+1,r,ll,rr));
        return res;
    }
}stmin;
class Fenwick{
private:
    int t[MAXN];
    inline int lowbit(int x){
        return x&(-x);
    }
public:
    inline void reset(){
        memset(t,0,sizeof(t));
    }
    inline void add(int pos,int v){
        while(pos<=n){
            t[pos]+=v;
            pos+=lowbit(pos);
        }
    }
    inline int ask(int pos){
        int res=0;
        while(pos>0){
            res+=t[pos];
            pos-=lowbit(pos);
        }
        return res;
    }
    inline int ask_range(int l,int r){
        if(l>r) return 0;
        if(l<=1) return ask(r);
        else return ask(r)-ask(l-1);
    }
}fw;
int main(){
    rd(n);rd(m);
    for(int i=1;i<=n;i++){
        rd(a[i]);
        buck[i]=a[i];
    }
    for(int i=1;i<=m;i++){
        rd(qry[i].first);rd(qry[i].second);
        qry[i].id=i;
    }

    sort(buck+1,buck+1+n);
    len=unique(buck+1,buck+1+n)-buck-1;
    for(int i=1;i<=n;i++)
        na[i]=lower_bound(buck+1,buck+1+len,a[i])-buck;

    for(int i=1,res;i<=n;i++){
        res=stmax.query(1,1,len,na[i]+1,len);
        if(res==0) rg[i].first=1;
        else rg[i].first=res+1;
        stmax.update(1,1,len,na[i],i);
    }
    for(int i=n,res;i>=1;i--){
        res=stmin.query(1,1,len,na[i]+1,len);
        if(res==0x3f3f3f3f) rg[i].second=n;
        else rg[i].second=res-1;
        stmin.update(1,1,len,na[i],i);
    }

    sort(qry+1,qry+1+m);
    sort(rg+1,rg+1+n);
    for(int i=1,ptrqry=0,ptrrg=0;i<=n;i++){
        while(ptrrg<n && rg[ptrrg+1].first<=i){
            ptrrg++;
            fw.add(rg[ptrrg].second,1);
        }
        while(ptrqry<m && qry[ptrqry+1].first<=i){
            ptrqry++;
            ans[qry[ptrqry].id]+=fw.ask(qry[ptrqry].second-1);
        }

        if(ptrrg>=n && ptrqry>=m) break;
    }
    for(int i=1;i<=m;i++){
        ans[qry[i].id]+=fw.ask_range(qry[i].second,n);
        ans[qry[i].id]-=(qry[i].first-1)+(n-qry[i].second);
    }
    for(int i=1;i<=m;i++){
        wt(ans[i],'\n');
    }
    return 0;
}

T2 QOJ1173 Knowledge Is...

Problem

有 \(n\) 个区间,求最多能选出多少对区间,使得每对中的两个区间严格不交,一个区间至多属于一对区间,也可以不被选。

Solution

贪心。按左端点顺序遍历所有区间,开两个以右端点为关键字的小根堆,一个维护之前没有被匹配的区间,一个维护被匹配的区间对中右侧的那个区间,记当前区间为 \([l,r]\),堆顶的区间为 \([l',r']\)。

  • 如果没被匹配的区间堆顶 \(r'<l\),那么就可以匹配,否则一定不存在未匹配的区间可以与之配。
  • 如果被匹配的区间堆顶 \(r'<r\),那么可以让当前区间去匹配堆顶原先匹配的区间,而将堆顶抽出来变为未匹配的,这样一定是更优的,并且由于我们是按左端点顺序遍历,\(l'<l\),因此替换一定是合法的。
  • 如果仍无法匹配,那就塞入未匹配的堆中。
代码
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int MAXN=5e5+5;
int n,ans=0;
pii a[MAXN];
struct CMP{
    bool operator ()(const pii& a,const pii& b){
        return a.second>b.second;
    }
};
priority_queue<pii,vector<pii>,CMP>match,unmatch;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i].first>>a[i].second;
    }
    sort(a+1,a+1+n);
    for(int i=1;i<=n;i++){
        bool flag=0;
        if(!unmatch.empty()){
            auto it=unmatch.top();
            if(it.second<a[i].first){
                flag=1;
                ans++;
                unmatch.pop();
                match.push(a[i]);
            }
        }
        if(!flag && !match.empty()){
            auto it=match.top();
            if(it.second<a[i].second){
                flag=1;
                match.pop();
                match.push(a[i]);
                unmatch.push(it);
            }
        }
        if(!flag){
            unmatch.push(a[i]);
        }
    }
    cout<<ans<<endl;
    return 0;
}

T3 Codeforces Gym 102538H Horrible Cycles

Problem

有 \(2n\) 个点的二分图,左右各 \(n\) 个点,左侧第 \(i\) 个点与右侧第 \(j\in[1,a[i]]\) 个点有边,求图中有多少简单环(简单环:每个点只经过一次)。

Solution

将所有点重新排序,使得所有的左部点与它前面的所有右部点连边。

考虑到如果我们只保留 \(1\sim n\) 的点,环就会被拆成很多条链。

f[i][j] 为只从前 \(i\) 个点中选择点保留,形成了 \(j\) 条链的方案数,注意此时的链是钦定了顺序的链。

考虑转移:

  • 如果点 \(i\) 是右部点,那么加入后不会产生任何边,如果选择它,就会形成一个新的链。f[i][j]=f[i-1][j]+f[i-1][j-1]
  • 如果点 \(i\) 是左部点,那么加入后它会和前面所有右部点连边(这些边有些会被选入链中有些被弃用),如果选择它,就会将之前的链合并为一条,由于我们计数的是简单环,我们只能将当前点置于一条链中,相当于在 \(j\) 条链中分别选择一条与它的链尾相连,再选择一条与它的链头相连。f[i][j]=f[i-1][j]+j*(j-1)*f[i-1][j+1]

那么答案就是所有 \(i\) 的 f[i-1][1] 之和,表示 \(i\) 将这条链的两端连起来了,形成了一个环,并且要减去二元环数量 \(\sum a_i\),最后还需要除以 \(2\),因为链是有序的,每个环被算了两次。

由于每次状态转移只与上一次状态有关,可以压维。

代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=5005;
const LL P=1e9+7;
inline LL qpow(LL a,LL b){
    a%=P;
    LL res=1;
    while(b){
        if(b&1) res=res*a%P;
        a=a*a%P;
        b/=2;
    }
    return res;
}
int n,a[MAXN];
LL ans=0,sum=0,f[MAXN];
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        sum=(sum+(LL)a[i])%P;
    }
    sort(a+1,a+1+n);
    f[0]=1;
    for(int i=1;i<=n;i++){
        for(int j=a[i-1]+1;j<=a[i];j++){
            for(int k=j;k>=1;k--){
                f[k]=(f[k]+f[k-1])%P;
            }
        }
        ans=(ans+f[1])%P;
        for(int j=1;j<=a[i];++j){
            f[j-1]=(f[j-1]+1LL*j*((j-1+P)%P)%P*f[j]%P)%P;
        }
    }
    ans=(ans-sum+P)%P;
    cout<<ans*qpow(2,P-2)%P<<endl;
    return 0;
}

标签:const,比赛,int,res,LL,NFLS,区间,MAXN,241014
From: https://www.cnblogs.com/SkyNet-PKN/p/18466481

相关文章

  • 临时起意加塞 比赛总结
    临时起意加塞T1HunteT2DefenceT3Connect从今天开始我要好好写比赛总结赛时思路今天由于没有特别睡醒,所以考试前一个小时状态不佳。T1看见45pts可做,决定写状压dp。写了一个小时没写出来,然后改为去写状压+记搜,一下子就写出来了。T2上有策略的失误。T2是线段树......
  • 人工智能是如何预测足球比赛?大小球亚盘数据分析推荐
    今天的文章主要包含了三部分内容:1,AI预测足球的过程。2,举例说明。3,影响AI预测准确率的原因。AI预测足球比赛的过程,其实并不复杂,主要就是下面几步,大家可以和自己平时预测比赛做个对照,看看我们和机器的区别在哪里:1,评估影响比赛结果的因素AI通过大模型的训练数据和知识库,运用机......
  • 中国矿业大学谢同学专访,获得全国比赛一等奖,已保送至南京大学GIS专业
    谢同学个人经历:中国矿业大学,专业排名第二大三期间参加新中地和中国矿业大学联合举办的webgis校企联合实训;实训结业后,谢同学和队友将实训作业进行深化改造后参加A类比赛,获得全国大学创新创业智能大赛开发设计竞赛全国一等奖;目前推免至南京大学地图学与地理信息系统专业就读......
  • 第一次比赛总结
    第一次比赛总结1.做题情况flowersflowerluckyabctotal(总分)名次30100801023032.赛中表现flowers考虑到c<=d,后将样例过后便没管,flower直接将暴力写出,lucky快速写完,abc第一个样例过后,第二个样例错误后更新做法将第二个样例k.o3.比赛题解flowers......
  • datawhale-大模型攻防比赛实践-第一次行动
    最近刚好是在写智能信息安全的教程,最后一章准备讲内容安全,里面有一节探讨大模型安全的内容,刚好可以拿比赛的内容当案例。首先,可以通过modelscope平台获得GPU使用权限。然后你就可以跑baseline了我这里试着跑了一下,如果是GPU版本就比较流畅,CPU会被卡死。但是呢,一天就只能提交一次......
  • jsp大学生比赛赛事信息管理8jmqc程序+源码+数据库+调试部署+开发环境
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表用户,公告类型,公告信息,赛事信息,报名信息,赛事队伍,加入队伍,赛事成绩开题报告内容一、开题报告名称大学生比赛赛事信息管理系统二、研究的目的、意义随着......
  • Java基于SpringBoot的高校体育运动会比赛项目报名系统 +Vue[毕业设计]
    文末获取资源,收藏关注不迷路文章目录项目介绍技术介绍项目界面关键代码目录项目介绍在高等教育体系中,体育运动会不仅是增强学生体质、培养团队精神的重要途径,也是校园文化的重要组成部分。然而,传统的高校体育运动会报名方式往往存在诸多不便,如报名流程繁琐、信息更......
  • 一堆比赛题
    T1题意简述:给定一个序列\(a\),每次将\(a\)的第一个元素加入\(b\)的末尾然后翻转\(b\),求最后的\(b\)是什么。\(n\le10^6\)。考虑模拟一下这个过程,发现就是奇数次次向最后添加,偶数次次向开头添加,最后再翻转\(n\bmod2\)次。T2题意简述:定义两点的距离为\(|x_i-x_j|^3+......
  • 比赛记录(51~60)
    51CSP-S模拟赛321得分题目T1T2T3T4总分得分\(4\)\(20\)\(11\)\(27\)\(62\)排名:rank\(9\)。真正炸裂的一集。2题解T1考虑到边数较少,于是考虑能不能枚举边相关信息。通过部分分可以有如下讨论:\(c_u\nec_v\)时,意味着原先两点间有的边没了,那么两......
  • 牛客 9.29 对标 ABC 比赛题面
    ABCDEF(E'shard)输入52214331524G......