【NOIP模拟8.12】

T1 BRS

题意:求区间最大连续子段和
题解:
60分做法:在每一段里贪心地做LIS,复杂度 O(nm)
100分做法:用线段树维护一个 lmax,rmax,max,sum,做区间合并即可

//by sdfzchy
#include<map>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#define mp make_pair
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
int n,m;
const int maxn=500050;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x*f;
}

inline void print(int x)
{
    if (x<0){putchar('-'); x=-x;}
    if (x>=10) print(x/10);
    putchar(x%10+'0');
}


struct segment_tree
{
    struct tree_node{int sum,lmax,rmax,max;}t[maxn*4+5];
    tree_node merge(tree_node lson,tree_node rson)
    {
        tree_node ret;
        ret.sum=lson.sum+rson.sum;
        ret.lmax=max(lson.lmax,lson.sum+rson.lmax);
        ret.rmax=max(rson.rmax,rson.sum+lson.rmax);
        ret.max=max(max(lson.max,rson.max),lson.rmax+rson.lmax);
        return ret;
    }
    void Build(int l,int r,int rt)
    {
        if(l==r)
        {
            t[rt].max=read();
            t[rt].lmax=t[rt].rmax=t[rt].sum=t[rt].max;
            return;
        }
        int m=(l+r)>>1;
        Build(l,m,rt<<1);
        Build(m+1,r,rt<<1|1);
        t[rt]=merge(t[rt<<1],t[rt<<1|1]);
    }
    void Update(int p,int x,int l,int r,int rt)
    {
        if(l==r)
        {
            t[rt].lmax=t[rt].rmax=t[rt].sum=t[rt].max=x;
            return;
        }
        int m=(l+r)>>1;
        if(p<=m) Update(p,x,l,m,rt<<1);
        if(p>m)  Update(p,x,m+1,r,rt<<1|1);
        t[rt]=merge(t[rt<<1],t[rt<<1|1]);
    }
    tree_node Query(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&R>=r) return t[rt];
        int m=(l+r)>>1,flag=0;
        tree_node ans;
        if(L<=m) ans=Query(L,R,l,m,rt<<1),flag=1;
        if(R>m)  ans=flag?merge(ans,Query(L,R,m+1,r,rt<<1|1)):Query(L,R,m+1,r,rt<<1|1);
        return ans;
    }

}T;

int main()
{
    freopen("BRS.in","r",stdin);
    freopen("BRS.out","w",stdout);
    n=read(),m=read();
    T.Build(1,n,1);
    for(int i=1,a,b,c;i<=m;i++)
    {
        a=read(),b=read(),c=read();
        if(a==2) T.Update(b,c,1,n,1);
        else printf("%d\n",T.Query(b,c,1,n,1).max);
    }
    return 0;
}

T2 fyfy

题意:开始时在0处,每次走不超过k步,求到n的方案数
题解:很容易写出递推式 f[i]=min(k,i)j=1f[ij] ,发现这个东西是一个线性递推,矩阵加速即可,复杂度 O(k3logn)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define LL long long
const int mod=7777777;
LL n;
int k;

struct Matrix
{
    LL a[15][15];
    Matrix() {memset(a,0,sizeof(a));}
    Matrix operator *(const Matrix& b)const
    {
        Matrix ret;
        for(int i=1;i<=k;i++)
            for(int j=1;j<=k;j++)
                for(int l=1;l<=k;l++)
                    ret.a[i][j]+=(a[i][l]*b.a[l][j])%mod;
        return ret;
    }       
};



Matrix ksm(Matrix a,LL b)
{
    b--;
    Matrix ret;
    ret=a;
    for(;b;b>>=1,a=a*a)
    {
        if(b&1) ret=ret*a;  
    }

    return ret; 
}

void work()
{
    Matrix ans,e;
    ans.a[1][1]=1;
    for(int i=1;i<=k;i++) e.a[1][i]=1;
    for(int i=2;i<=k;i++) e.a[i][i-1]=1;
    e=ksm(e,n);
    ans=e*ans;
    printf("%lld\n",ans.a[1][1]);
}

int main()
{
    freopen("fyfy.in","r",stdin);
    freopen("fyfy.out","w",stdout);
    scanf("%d%lld",&k,&n);
    work();
    return 0;   
}

T3 olddriver

题意:求矩形面积并
题解:线段树扫描线,复杂度 O(nlogn)
ps:数据范围水,没写线段树,复杂度 O(n2)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
LL n,ecnt,ha[1000],vis[100010],ans;
struct seg
{
    LL x,l,r,flag;
    bool operator <(const seg& a)const
    {
        return x<a.x;
    }
}e[1010];

int main()
{
    freopen("olddriver.in","r",stdin);
    freopen("olddriver.out","w",stdout);
    scanf("%lld",&n);
    LL a,b,c,d;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
        ha[2*i-1]=a,ha[2*i]=c;
        e[++ecnt].l=a,e[ecnt].r=c,e[ecnt].flag=1,e[ecnt].x=b;
        e[++ecnt].l=a,e[ecnt].r=c,e[ecnt].flag=-1,e[ecnt].x=d;
    }
    sort(e+1,e+ecnt+1);
    sort(ha+1,ha+2*n+1);
    int m=unique(ha+1,ha+2*n+1)-ha-1;
    for(int i=1;i<=ecnt;i++)
    {
        e[i].l=lower_bound(ha+1,ha+m+1,e[i].l)-ha;
        e[i].r=lower_bound(ha+1,ha+m+1,e[i].r)-ha;
    }
    int sum=0;
    for(int i=1;i<=ecnt;i++)
    {
        sum=0;
        for(int j=1;j<=m;j++)
        {
            if(vis[j]>0) sum+=ha[j]-ha[j-1];
            if(vis[j]<0) sum-=ha[j]-ha[j-1]; 
        }
        ans+=(e[i].x-e[i-1].x)*sum;
        int tmp=e[i].x;
        while(e[i].x==tmp)
        {
            for(int j=e[i].l+1;j<=e[i].r;j++)
                vis[j]+=e[i].flag;
            i++;
        }
        i--;
    }
    printf("%lld\n",ans);
    return 0;   
}

又是一套信心题hhh
怎么感觉是线段树专题呢QAQ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NOI(全国青少年信息学奥林匹克竞赛)模拟赛的测试数据是指用于评测参赛选手的程序的输入和对应的输出。测试数据是非常重要的,因为它决定了参赛选手的程序能否正确地解决问题。 在NOI模拟赛中,测试数据具有以下特点: 1.充分覆盖:测试数据应涵盖各种可能的输入情况,包括边界条件和极端情况。通过提供不同的测试数据,可以考察选手对问题的全面理解和解决能力。 2.随机性和均衡性:为了公平起见,测试数据应该是随机生成的,而不是针对某个特定算法或解法设计的。同时,测试数据应该是均衡的,即各种情况的概率应该大致相等,以避免偏向某些解法。 3.合理性和可行性:测试数据应该是合理和可行的,即符合题目要求的输入数据,并且是选手能够通过编写程序来处理的。测试数据应该考虑到程序的限制和时间复杂度,以充分测试选手的编程能力。 NOI模拟赛的测试数据通常由经验丰富的考题组负责生成。他们会根据题目的要求和限制,设计出一组合理、充分、随机和均衡的测试数据,以确保参赛选手的程序在各种情况下都能正确运行,并且能通过性能测试。 总之,测试数据在NOI模拟赛中起到了至关重要的作用,它既考察了选手对问题的理解和解决能力,又提高了选手编程的技巧和效率。同时,合理和恰当的测试数据也是公平竞赛的保证,确保每个参赛选手有相同的机会和条件进行竞争。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值