AtCoder Beginner Contest 178 题解

希望更丰富的阅读体验?点这里

一、题解

A.Not

题目大意

输入 0 0 0 1 1 1 ,如果这个数是 0 0 0 ,输出 1 1 1 ,否则输出 0 0 0

分析

请允许我略。

代码

不用贴了吧……

B.Product Max

题目大意

给定整数 a , b , c , d a,b,c,d a,b,c,d − 1 0 9 ≤ a , b ≤ 1 0 9 , − 1 0 9 ≤ c , d ≤ 1 0 9 -10^9 \le a,b \le 10^9,-10^9 \le c,d \le 10^9 109a,b109,109c,d109)。若整数 x , y x,y x,y 满足 a ≤ x ≤ b , c ≤ y ≤ d a \le x \le b,c \le y \le d axb,cyd ,求 x × y x \times y x×y 的最大值。

分析

首先对于 a , b , c , d a,b,c,d a,b,c,d 为正整数的情况,有一个结论:如果 x × y x \times y x×y 最大,那么 x = b , y = a x=b,y=a x=b,y=a

但是 a , b , c , d a,b,c,d a,b,c,d 可以为负,这时 x = a x=a x=a b b b y = c y=c y=c d d d 都行,只要取 a × c , a × d , b × c , b × d a \times c,a \times d,b \times c,b \times d a×c,a×d,b×c,b×d 四个数中的最大值就可以了。

代码

#include <cstdio>
#define max(a,b) ((a)>(b)?(a):(b))
int main(){
    long long a,b,c,d;
    scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
    printf("%lld\n",max(a*c,max(a*d,max(b*c,b*d))));
    return 0;
}

C.Ubiquity

题目大意

有多少个长度为 N N N 1 ≤ N ≤ 1 0 6 1 \le N \le 10^6 1N106)的序列 A 1 , A 2 , . . . A N A_1,A_2,...A_N A1,A2,...AN 满足以下条件:

  • 0 ≤ A i ≤ 9 0 \le A_i \le 9 0Ai9
  • 至少有一个数等于 0 0 0
  • 至少有一个数等于 9 9 9

结果对 1 0 9 + 7 10^9+7 109+7 取模。

分析

如果把问题想成求组合数就完全错了,因为 N = 3 N=3 N=3 时数列 { 0 , 1 , 9 } \{0,1,9\} {0,1,9} 也是可以的,因此只能换一个角度。

在仅有 0 ≤ A i ≤ 9 0 \le A_i \le 9 0Ai9 的条件下,数列个数显然是 1 0 N 10^N 10N

1 ≤ A i ≤ 9 1 \le A_i \le 9 1Ai9 ,即没有 A i = 0 A_i=0 Ai=0 时,个数为 9 N 9^N 9N

同理,没有 A i = 9 A_i=9 Ai=9 时,个数也为 9 N 9^N 9N

如果既没有 A i = 9 A_i=9 Ai=9 ,又没有 A i = 0 A_i=0 Ai=0 ,即 2 ≤ A i ≤ 8 2 \le A_i \le 8 2Ai8 时,数列个数为 8 N 8^N 8N

综上所述,运用容斥原理,结果为 1 0 N − 9 N − 9 N + 8 N 10^N-9^N-9^N+8^N 10N9N9N+8N ,可以把每种情况看成一个集合,这样好想一点。

代码

#include <cstdio>
#define mod 1000000007
long long pow(long long a,int n){//注意要用快速幂!
    long long base=a,ans=1;
    while(n){
        if(n&1) ans=ans*base%mod;
        base=base*base%mod,n>>=1;
    }
    return ans;
}
int main(){
    int n;scanf("%d",&n);
    printf("%lld\n",(pow(10,n)-pow(9,n)-pow(9,n)+pow(8,n))%mod);
    return 0;
}

但如果把这份代码交上去后,会WA掉三四个点,原因是:

取模!

1 0 N 10^N 10N 9 N 9^N 9N 分别取模后,原来的大小关系有可能发生改变(在 N N N 极大的时候),因此一定要将取模后的结果加上模数再取模,防止刚才的情况。

D.Redistribution

题目大意

有多少个数列既满足数列中每个数是大于等于 3 3 3 的整数,又满足所有数的和等于 S S S 1 ≤ S ≤ 2000 1 \le S \le 2000 1S2000)?结果对 1 0 9 + 7 10^9+7 109+7 取模。

分析

求方案数首先考虑计数类DP(動的計画法)或递推。设 f [ i ] f[i] f[i] 表示所有数和为 i i i 时数列的个数,那么数列中凑成和为 i i i 的数只能是 3 , 4 , 5 , . . . , i 3,4,5,...,i 3,4,5,...,i

那么数列的最后一个数只能是 3 , 4 , 5 , . . . , i 3,4,5,...,i 3,4,5,...,i ,假设有 x x x 个数,对于前 x − 1 x-1 x1 个数,方案数为 f [ i − 3 ] , f [ i − 4 ] , . . . , f [ i − i ] f[i-3],f[i-4],...,f[i-i] f[i3],f[i4],...,f[ii] ,因此得到转移方程:

f [ i ] = f [ i − 3 ] + f [ i − 4 ] + f [ i − 5 ] + . . . + f [ 0 ] f[i]=f[i-3]+f[i-4]+f[i-5]+...+f[0] f[i]=f[i3]+f[i4]+f[i5]+...+f[0]

由于 f [ i − 1 ] = f [ i − 4 ] + f [ i − 5 ] + . . . + f [ 0 ] f[i-1]=f[i-4]+f[i-5]+...+f[0] f[i1]=f[i4]+f[i5]+...+f[0]

所以 f [ i ] = f [ i − 1 ] + f [ i − 3 ] f[i]=f[i-1]+f[i-3] f[i]=f[i1]+f[i3]

初始化: f [ 0 ] = 1 f[0]=1 f[0]=1

代码

#include <cstdio>
long long f[2003]={0,0,0,1};
int main(){
    int s;scanf("%d",&s);
    for(int i=4;i<=s;i++)
    	f[i]=(f[i-1]+f[i-3])%1000000007;
    printf("%lld\n",f[s]);
    return 0;
}

E.Dist Max

题目大意

平面上给定 N N N 个点( 1 ≤ N ≤ 2 × 1 0 5 1 \le N \le 2 \times 10^5 1N2×105)的坐标( 1 ≤ x , y ≤ 1 0 9 1 \le x,y \le 10^9 1x,y109 且都为整数),求两点之间最大的曼哈顿距离。

分析

因为不能用 n 2 n^2 n2 算法了,所以可以分类讨论:

设最大距离 d i s = ∣ x i − x j ∣ + ∣ y i − y j ∣ dis=|x_i-x_j|+|y_i-y_j| dis=xixj+yiyj

x i ≥ x j , y i ≥ y j : x_i \ge x_j,y_i \ge y_j: xixj,yiyj:

原式 = x i − x j + y i − y j =x_i-x_j+y_i-y_j =xixj+yiyj
= ( x i + y i ) − ( x j + y j ) =(x_i+y_i)-(x_j+y_j) =(xi+yi)(xj+yj)

x i ≥ x j , y i < y j : x_i \ge x_j,y_i<y_j: xixj,yi<yj:

原式 = x i − x j + y j − y i =x_i-x_j+y_j-y_i =xixj+yjyi
= ( x i − y i ) − ( x j − y j ) =(x_i-y_i)-(x_j-y_j) =(xiyi)(xjyj)

x i < x j , y i ≥ y j : x_i<x_j,y_i \ge y_j: xi<xj,yiyj:

原式 = x j − x i + y i − y j =x_j-x_i+y_i-y_j =xjxi+yiyj
= − ( x i − y i ) + ( x j − y j ) =-(x_i-y_i)+(x_j-y_j) =(xiyi)+(xjyj)

x i < x j , y i < y j : x_i<x_j,y_i<y_j: xi<xj,yi<yj:

原式 = x j − x i + y j − y i =x_j-x_i+y_j-y_i =xjxi+yjyi
= − ( x i + y i ) + ( x j + y j ) =-(x_i+y_i)+(x_j+y_j) =(xi+yi)+(xj+yj)

发现了什么?

结果的绝对值只有 ( x i + y i ) − ( x j + y j ) , ( x i − y i ) − ( x j − y j ) (x_i+y_i)-(x_j+y_j),(x_i-y_i)-(x_j-y_j) (xi+yi)(xj+yj),(xiyi)(xjyj) 两种结果,取最大值即可。

所以维护每一个 x i + y i x_i+y_i xi+yi x i − y i x_i-y_i xiyi ,分别排序就可以了。

代码

#include <cstdio>
#include <algorithm>
int n,a[200003],b[200003],x,y;//a记录x+y,b记录x-y
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&x,&y);
        a[i]=x+y,b[i]=x-y;
    }
    std::sort(a+1,a+1+n);
    std::sort(b+1,b+1+n);//排序
    printf("%d\n",std::max(a[n]-a[1],b[n]-b[1]));
    return 0;
}

F.Contrast

还没想出来QAQ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值