2018.7.20模拟考试

这次的题...很水...然而还是差点爆零

T1 题目简述:给定一个序列,求区间最大子段和(带修改操作)。

             n<=500000,m<=100000

   解题思路:线段树维护即可。(GSS3原题...数据范围都不变...出题人好懒

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int n,m,a[500010];
struct uio{
    uio(){lmx=rmx=mx=-INF;}
    int lmx,rmx,mx,sum;
}tree[2000010];
void pushup(int x)
{
    int ls=(x<<1),rs=((x<<1)|1);
    tree[x].mx=max(tree[ls].rmx+tree[rs].lmx,max(tree[ls].mx,tree[rs].mx)); 
    tree[x].lmx=max(tree[ls].lmx,tree[ls].sum+tree[rs].lmx);
    tree[x].rmx=max(tree[rs].rmx,tree[rs].sum+tree[ls].rmx);
    tree[x].sum=tree[ls].sum+tree[rs].sum;
}
void build(int now,int l,int r)
{
    if(l==r)
    {
        tree[now].mx=tree[now].lmx=tree[now].rmx=tree[now].sum=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build((now<<1),l,mid);
    build(((now<<1)|1),mid+1,r);
    pushup(now);
}
void revise(int now,int l,int r,int to,int k)
{
    if(l==r)
    {
        tree[now].mx=tree[now].lmx=tree[now].rmx=tree[now].sum=k;
        return;
    }
    int mid=(l+r)>>1;
    if(to<=mid) revise((now<<1),l,mid,to,k);
    else revise(((now<<1)|1),mid+1,r,to,k);
    pushup(now);
}
uio query(int now,int l,int r,int L,int R)
{
    if(L<=l&&r<=R) return tree[now];
    int mid=(l+r)>>1;
    if(L>mid) return query(((now<<1)|1),mid+1,r,L,R);
    if(R<=mid) return query((now<<1),l,mid,L,R);
    if(L<=mid&&mid<R)
    {
        uio ans;
        uio a=query((now<<1),l,mid,L,R);
        uio b=query(((now<<1)|1),mid+1,r,L,R);
        ans.mx=max(a.rmx+b.lmx,max(a.mx,b.mx));
        ans.lmx=max(a.lmx,a.sum+b.lmx);
        ans.rmx=max(b.rmx,b.sum+a.rmx);
        ans.sum=a.sum+b.sum;
        return ans;
    }
}
int main()
{
    freopen("BRS.in","r",stdin);
    freopen("BRS.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        if(u==2) revise(1,1,n,v,w);
        if(u==1)
        {
            if(v>w) swap(v,w);
            printf("%d
",query(1,1,n,v,w).mx);
        }
    }
    return 0;
}

T2 题意简述:有n个格子,每次最多走k个,问走到第n格有多少种走法。答案对7777777取模。

             1<=n<=2^31-1,1<=k<=10

   解题思路:一看n这么大,考虑矩阵加速。

             发现递推过程类似斐波那契数列,因此构造矩阵如下。(以k=5为例)

0 0 0 0 1
0 1 0 0 1
0 0 1 0 1
0 0 0 1 1

             然后求qpow(matrix.a,n)即可。

             注:以下代码来自sdfzsyq大佬。(其实就是我懒...

#include<iostream> 
#include<cstdio>
#include<cstring>
#include<cmath>
#define LL long long

using namespace std;
const int mod = 7777777;

int n,k;

struct Mat{
    LL a[15][15];
    Mat(){
        memset(a,0,sizeof(a));
    }
    Mat operator*(const Mat &h){
        Mat c;
        for(register int i=1;i<=k;i++)
            for(register int j=1;j<=k;j++)
                for(register int o=1;o<=k;o++)
                    (c.a[i][j]+=(a[i][o]%mod*h.a[o][j]%mod))%=mod;
        return c;
    }
}f,ans,st;

inline void fast_pow(Mat A,int b){
    for(;b;b>>=1){
        if(b&1) st=st*A;
        A=A*A;
    }
}

int main(){
    freopen("fyfy.in","r",stdin);
    freopen("fyfy.out","w",stdout);
    scanf("%d%d",&k,&n);
    if(k==1){
        puts("1");
        return 0;
    }
    for(register int i=2;i<=k;i++)  f.a[i][i-1]=1;
    for(register int i=1;i<=k;i++)  f.a[i][k]=1;
    for(register int i=1;i<=k;i++)  st.a[i][i]=1;
    fast_pow(f,n);
    printf("%lld
",st.a[k][k]);
    return 0;
}

T3 题意简述:求矩形面积并。

             n<=100,坐标数值绝对值<=10^8

   解题思路:扫描线。

             由于数据太水,因此本题可以用O(n^2)水过。

             坐在我旁边的ErkkiErkko大佬说n应该开到10^6。

             如果按照ErkkiErkko大佬的数据范围,本题代码应加上线段树优化+卡常。

             复杂度O(nlogn)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define inf 100000001
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
ll n,ans,a[210],sec[210][110],sec1[210][110],vis[110];
struct uio{
    ll l,r,u,d;
}mat[110];
struct oiu{
    ll u,d;
}tmp[110];
bool cmp(oiu x,oiu y)
{
    if(x.u==y.u)
        return x.d>y.d;
    return x.u>y.u;
}
int main()
{
    freopen("olddriver.in","r",stdin);
    freopen("olddriver.out","w",stdout);
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)
    {
        scanf("%lld%lld%lld%lld",&mat[i].l,&mat[i].d,&mat[i].r,&mat[i].u);
        a[i*2-1]=mat[i].l,a[i*2]=mat[i].r;
    }
    sort(a+1,a+1+2*n);
    ll num=unique(a+1,a+1+2*n)-a-1;
    for(ll i=1;i<=n;i++)
    {
        ll u=lower_bound(a+1,a+1+num,mat[i].l)-a;
        sec[u][++sec[u][0]]=i,sec1[u][++sec1[u][0]]=mat[i].l;
        ll v=lower_bound(a+1,a+1+num,mat[i].r)-a;
        sec[v][++sec[v][0]]=i,sec1[v][++sec1[v][0]]=mat[i].r;
    }
    for(ll i=1;i<=200;i++)
    {
        memset(tmp,0,sizeof(tmp));
        ll cnt=0,num=0;
        ll j=1;
        while(sec[i][j]!=0)
        {
            if(!vis[sec[i][j]])
                vis[sec[i][j]]=1;
            else vis[sec[i][j]]=0;
            j++;
        }
        for(ll k=1;k<=n;k++)
            if(vis[k])
                tmp[++cnt].u=mat[k].u,
                tmp[cnt].d=mat[k].d;
        sort(tmp+1,tmp+1+cnt,cmp);
        ll mu=tmp[1].u,md=tmp[1].d;
        for(ll k=2;k<=cnt;k++)
        {
            if(tmp[k].u<md)
                num-=md-tmp[k].u;
            md=min(md,tmp[k].d);
        }
        num+=mu-md;
        ans+=num*(sec1[i+1][1]-sec1[i][1]);
    }
    printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/water-radish/p/9342270.html