博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

【考试总结】AHSOFNU&QZQZ test10-25

Tips:

1.评测在 Windows 下的 lemon 中进行,开启 O2 优化,开大栈空间;

2.题目较水,无论 AK 与否,都请不要 D 出题人。

题目名称 切题 开车 学习

英文名称 problem car study

输入文件名 problem.in car.in study.in

输出文件名 problem.out car.out study.out

时间限制 1s 1s 1s

内存限制 128MB 128MB 128MB

题目类型 传统 传统 传统

Problem

 

切题(problem)

Description

小 Z 和小 G 都是切题好手,他们经常抢着切题,今天他们已经 决定好了 n 道要切的题目并准备按照顺序切掉这些题。每道题都有一 个难度值 di,两个人都想自己切掉的题难度值之和最大,但他们又不 屑于切对方切过的题,于是两人制定了如下规则:一开始,决定谁切 下一道题的权利在作为老大的小 Z 手里,拥有这个权利的人可以指定 谁切下一道题,当被指定的那个人切完题后,这个权利会转移到没切 这道题的那个人手上(可以是自己)。两人都很强,所以他们总是进 行最优的决策以使自己切到的题难度值之和最大。F 大爷想知道他们 最后各自切的题的难度值之和。

Input Format

 第一行一个正整数 n,表示题数。 接下来 n 个正整数 di,依次表示第 i 道要切的题的难度值。

Output Format

 输出两个用空格隔开的整数,分别表示小 Z 和小 G 切掉的 题的难度值之和。

Sample Input

 4 2 3 3 3

Sample Output

 6 5

Hint

 对于 20%的数据,n<=5; 对于 40%的数据,n<=50; 对于 60%的数据,n<=500; 对于 80%的数据,n<=5000; 对于 100%的数据,n<=50000,di<=100。

Solution

f[i]表示有主动权的人i-n能获得的最大值
则没有主动权的人的最大值为sum[i]-f[i]
转移时选择保持主动权还是失去主动权

#include<cstdio>
#include<iostream>

int n;
int a[50005];
int f[50005];
int sum[50005];

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    for (int i=n;i>=1;i--) sum[i]=sum[i+1]+a[i];
    for (int i=n;i>=1;i--)
        f[i]=std::max(f[i+1],sum[i+1]-f[i+1]+a[i]);
    printf("%d %d",f[1],sum[1]-f[1]);
}

 

开车(car)

Description

 老司机小 Q 要在一个十字路口指挥车队开车,这个十字路口可 以描述为一个 n*n 的矩阵,其中第 2 行到第 n-1 行都各有一道横向车 道,第 2 列到第 n-1 列都各有一条纵向车道。飙车开始前,小 Q 可以 在每条车道的两端(横向车道为从左到右第 1 格和第 n 格,纵向车道 为从上到下的第 1 格和第 n 格)安置一辆大卡车。安置结束后,小 Q 可以下令让所有大卡车同时向车道的另一端行驶,所有的卡车速度都 相同。小 Q 要合理安排这些卡车,使得它们在行驶过程中不会相撞; 另外一些格子上有小 C 放置的巨石,这些格子不能通过卡车。小 Q 希望安置的卡车最多,请你求出最多的卡车数。

Input Format

 第一行两个非负整数 n 和 m,分别表示十字路口大小和巨石数 量。接下来 m 行,每行两个正整数 xi,yi,表示在第 xi 行第 yi 列有一 个巨石。

Output Format

 输出一个整数,表示答案。

Sample Input

 4 3 3 1 3 2 3 3

Sample Output

 1

Hint

 对于 20%的数据,n<=5; 对于 40%的数据,n<=10; 对于 70%的数据,n<=1000; 对于 100%的数据,3<=n<=200000,m<=200000。

Solution

在无石子的情况,一定有2n-4的可放位置
放置了石子,则某行某列不能放石子,也就少了一个放置位置
ans--;
n&1时,中间的行列会冲突,不能放置2个,ans--

#include<cstdio>

int n,m;
bool tx[200005],ty[200005];
int ans;

int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        tx[x]=1;
        ty[y]=1;
    }
    for (int i=2;i<n;i++)
    {
        ans+=2-tx[i]-ty[i];
    }
    if ((n&1)&&!tx[n/2+1]&&!ty[n/2+1]) ans--;
    printf("%d",ans);
}

 

学习(study)

Description

 巨弱小 D 准备学习,有 n 份学习资料给他看,每份学习资料的 内容可以用一个正整数 ai 表示。小 D 如果在一天内学习了多份资料, 他只能记住这些资料的内容表示成的整数的最大公约数的部分。学习 若干份资料得到的收益是小 D 记下的内容之和,也就是学习的资料 数乘上这些资料内容的最大公约数。小 D 今天准备挑一段连续的资 料来学习,请你告诉他最大的收益是多少。

Input Format

 第一行一个正整数 n,表示资料数。 接下来 n 个正整数 ai,分别表示每份资料的内容。

Output Format

 输出一个整数,表示答案。

Sample Input

 5 30 60 20 20 20

Sample Output

 80

Hint

 对于 20%的数据,n<=100; 对于 40%的数据,n<=1000; 对于 70%的数据,n<=100000; 对于 100%的数据,n<=500000,ai<=10^9。

Solution

a[i]表示到右端点gcd不同的一段区间
相邻区间gcd相同就合并,num[i]表示该区间长度
ans=max{a[j]*len} len=从右端点到该段区间间的每段区间长度

#include<cstdio>
#include<iostream>

int n,tot,len,x;
int a[500005],num[500005];
long long ans;

int gcd(int a,int b)
{
    if (b==0) return a;
    return gcd(b,a%b);    
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        if (!tot)
        {
            a[++tot]=x;
            num[tot]=1;
            continue;
        }
        for (int j=1;j<=tot;j++) a[j]=gcd(a[j],x);
        int last=1;a[++tot]=x,num[tot]=1;
        for (int j=2;j<=tot;j++)
        {
            if (a[j]==a[last]) num[last]+=num[j];
            else a[++last]=a[j],num[last]=num[j];
        }
        tot=last;
        len=0;
        for (int j=tot;j;j--)
        {
            len+=num[j];
            ans=std::max(ans,1ll*a[j]*len);
        }
    }
    printf("%lld",ans);
}

 

posted @ 2017-10-26 10:31  JadeDark  阅读(216)  评论(1编辑  收藏  举报