五校联考解题报告

Day 1(题目在这儿)

T1 骰子

题意:

有一个 的网络的左上角(1,1)有一个

有一个骰子上面为  1 ,下面为6 左面为 4,右面为 3,前面为 2,后面为 5),先从左滚

右然后滚下去滚到最左边…..,每次记最上边点数为每次得分,问滚完以后可以得多少分?

解:

开始定义shang=1,xia=6,zuo=4…

暴力:

对于 数据, 模拟在每个格子上的状态,数据可以到10000左右不会超时。

而每次滚动需要考虑三种操作。

①     向左滚

右变上,上变左,左变下,下变右。

LL solz()
{
    LL temp=shang;
    shang=you;you=xia;xia=zuo;zuo=temp;
    return shang;
}

②     向右滚

LL soly()
{
    LL temp=shang;
    shang=zuo;zuo=xia;xia=you;you=temp;
    return shang;
}

③     向下滚

LL sold()
{
    LL temp=shang;
    shang=hou;hou=xia;xia=qian;qian=temp;
    return shang;
}

对于100%的数据,需要观察一下筛子滚动的价值规律。

骰子对面相加价值为7,滚动一周价值为14,我们可以直接考虑滚动一行可以滚动多少周那么可以直接 14,然后一行剩余的最多枚举3次,时间复杂度优秀。

/***************************
一轮noip模拟考试 Day1 T1
--2018.8.26
***************************/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define LL long long
LL shang=1,xia=6,zuo=4,you=3,qian=2,hou=5;
LL n,m,sum,ans;
LL solz()
{
    LL temp=shang;
    shang=you;you=xia;xia=zuo;zuo=temp;
    return shang;
}
LL soly()
{
    LL temp=shang;
    shang=zuo;zuo=xia;xia=you;you=temp;
    return shang;
}
LL sold()
{
    LL temp=shang;
    shang=hou;hou=xia;xia=qian;qian=temp;
    return shang;
}
int main()
{
//    freopen("dice.in","r",stdin);
//    freopen("dice.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)
    {
        ans+=(m/4)*14;
        if(i%2==1&&m%4!=0)
        {
            ans+=shang;
            for(int j=1;j<m%4;j++)ans+=soly();            
        }
        else if(m%4!=0)
        {
            ans+=shang;
            for(int j=1;j<m%4;j++)ans+=solz();
        }
        sold();
    }
    printf("%lld",ans);
//    fclose(stdin);fclose(stdout);
}

T2 子序列

题意:

给定一个序列 .

求序列中有多少对三元组(I,j,k),满足 或者$a[i] \le a[j] \le a[k]$或者$a[k] \le a[j] \le a[i]$ 。

解:

对于20%枚举i,j,k即可。

对于50%, 处理某个数左边有多少大于它的数,有多少小于它的数,右边有多少…,然后枚举j点,所以每个点满足的三元组数量为

       左边大于$a[j]$的个数$\times$右边小的个数+左边小的个数$\times$右边大的个数

/*****************
考场50分代码
********************/
int main()
{
    freopen("sub.in","r",stdin);
    freopen("sub.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            if(a[j]>a[i])big[i]++;
            if(a[j]<a[i])small[i]++;
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            if(a[j]!=a[i])
            {
                if(a[j]>a[i]&&big[j])ans+=big[j];
                if(a[j]<a[i]&&small[j])ans+=small[j];
                ans%=mod;
            }
        }
    }
    printf("%d",ans);
    fclose(stdin);fclose(stdout);
}

对于100%的数据,则需要先离散化,用到了两个树状数组。

将复制离散化完的的数组排序,二分查找下标加到第一个树状数组里,区间[1,i]的和表示的为小于以i为下标的离散化数组中的数的个数,那么当枚举到i时,树状数组中区间[1,a[i]-1](a[i]表示在离散化序列中a[i]的位置)的和表示a[1--i]中小于a[i]的数字个数,总数为i-1个,那么小于等于a[i]的数字个数为树状数组中区间[1,a[i]]的和,那么大于a[i]的数的个数为i-1-query(1,a[i-1])。

这部分代码:

    for(int i=1;i<=n;i++)
    {
        a[i]=lower_bound(tmp+1,tmp+1+n,a[i])-tmp;
        l[i]=query(small,a[i]-1);    //比i小(左边)
        ll[i]=i-1-query(small,a[i]);
        add(small,a[i],1);
    }

同理处理右边的数,为了简便可以倒序枚举序列。

/************************
一轮Noip模拟赛Day 1 T2
--8.26
树状数组模板见于最后
*************************/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define LL long long
#define mod int(1e9+7)
LL n,a[200010],big[200020],small[200010],ans;
LL tmp[200020];
LL l[200020],r[200020],ll[200020],rr[200020];
int lowbit(int i){ return i & -i; }
LL query(LL *c,LL i)
{
    LL sum=0;
    while(i>0)
    {
        sum+=c[i];
        i-=lowbit(i);
    }
    return sum;
}
LL add(LL *c,int i,LL val)
{
    while(i<=n)
    {
        c[i]+=val;
        i+=lowbit(i);
    }
}
int main()
{
//    freopen("sub.in","r",stdin);
//    freopen("sub.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        tmp[i]=a[i];
    }
    sort(tmp+1,tmp+1+n);
    for(int i=1;i<=n;i++)
    {
        a[i]=lower_bound(tmp+1,tmp+1+n,a[i])-tmp;
        l[i]=query(small,a[i]-1);    //比i小(左边)
        ll[i]=i-1-query(small,a[i]);
        add(small,a[i],1);
    } 
    for(int i=n;i>=1;i--)
    {
        r[i]=query(big,a[i]-1);        //右边比i小的。 
        rr[i]=n-i-query(big,a[i]);
        add(big,a[i],1);
    }
    for(int i=1;i<=n;i++)
    {
        ans+=(l[i]*rr[i])%mod;
        ans+=(ll[i]*r[i])%mod;
        ans%=mod;
    } 
    printf("%lld\n",ans);
//    fclose(stdin);fclose(stdout);
}

T3 平面图

尚不会做正解,暂时只会10分。

子任务1:暴力搜索。

子任务3:n为奇数答案为0,偶数答案为2(开long long)

65递推式:$$ans = ((pow((pow(n, 2) % HA - (3 * n - 3) % HA) % HA, m % HA) % HA + ((n - 1) % HA) * ( (pow(3 - n, m) % HA) + (pow((1 - n) % HA, m) % HA) ) % HA) % HA)  + (pow(n, 2) % HA) - (3 * n - 1) % HA;$$

HA为%数。

Day 2 (here)

T1

题意:

给你n个区间,每次区间[l,r]内的数+1,求最大的点数是多少?

解:

对于30%数据,O(n)枚举区间每一个数每次+1,总复杂度O( )

对于另外20%, 离散化一下,枚举+1.

另外20% 据说是考虑不会离散化的学生。

对于100%,标程居然比暴力都好写。

离散化一下,每个区间的左端点处+1,r+1处-1,然后统计下前缀和,记录最大的答案。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define LL long long
LL l[200010],r[200020],tmp[400010];
LL n,ans,MAX,k,sum[433330];

int main()
{
    freopen("meizi.in","r",stdin);
    freopen("meizi.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld",&l[i],&r[i]);
        tmp[i*2-1]=l[i],tmp[i*2]=r[i];
    }
    sort(tmp+1,tmp+1+2*n);
    for(int i=1;i<=n;i++)
    {
        l[i]=lower_bound(tmp+1,tmp+1+2*n,l[i])-tmp;
        r[i]=lower_bound(tmp+1,tmp+1+2*n,r[i])-tmp;
        sum[l[i]]++;sum[r[i]+1]--;
    }
    for(int i=1;i<=2*n;i++)
    {
        sum[i]=sum[i-1]+sum[i];
        ans=max(ans,sum[i]);
    }
    printf("%lld",ans);
    fclose(stdin);fclose(stdout);
}

T2

 [无显示]你网页炸了!

T3

数学期望。

利用数学期望的线性性:期望的和等于和的期望。

猜你喜欢

转载自www.cnblogs.com/rmy020718/p/9540211.html