希望更丰富的阅读体验?点这里
一、题解
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 −109≤a,b≤109,−109≤c,d≤109)。若整数 x , y x,y x,y 满足 a ≤ x ≤ b , c ≤ y ≤ d a \le x \le b,c \le y \le d a≤x≤b,c≤y≤d ,求 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 1≤N≤106)的序列 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 0≤Ai≤9
- 至少有一个数等于 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 0≤Ai≤9 的条件下,数列个数显然是 1 0 N 10^N 10N 。
在 1 ≤ A i ≤ 9 1 \le A_i \le 9 1≤Ai≤9 ,即没有 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 2≤Ai≤8 时,数列个数为 8 N 8^N 8N 。
综上所述,运用容斥原理,结果为 1 0 N − 9 N − 9 N + 8 N 10^N-9^N-9^N+8^N 10N−9N−9N+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 1≤S≤2000)?结果对 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 x−1 个数,方案数为 f [ i − 3 ] , f [ i − 4 ] , . . . , f [ i − i ] f[i-3],f[i-4],...,f[i-i] f[i−3],f[i−4],...,f[i−i] ,因此得到转移方程:
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[i−3]+f[i−4]+f[i−5]+...+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[i−1]=f[i−4]+f[i−5]+...+f[0] ,
所以 f [ i ] = f [ i − 1 ] + f [ i − 3 ] f[i]=f[i-1]+f[i-3] f[i]=f[i−1]+f[i−3] 。
初始化: 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 1≤N≤2×105)的坐标( 1 ≤ x , y ≤ 1 0 9 1 \le x,y \le 10^9 1≤x,y≤109 且都为整数),求两点之间最大的曼哈顿距离。
分析
因为不能用 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=∣xi−xj∣+∣yi−yj∣ 。
x i ≥ x j , y i ≥ y j : x_i \ge x_j,y_i \ge y_j: xi≥xj,yi≥yj:
原式
=
x
i
−
x
j
+
y
i
−
y
j
=x_i-x_j+y_i-y_j
=xi−xj+yi−yj
=
(
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: xi≥xj,yi<yj:
原式
=
x
i
−
x
j
+
y
j
−
y
i
=x_i-x_j+y_j-y_i
=xi−xj+yj−yi
=
(
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<x_j,y_i \ge y_j: xi<xj,yi≥yj:
原式
=
x
j
−
x
i
+
y
i
−
y
j
=x_j-x_i+y_i-y_j
=xj−xi+yi−yj
=
−
(
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<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
=xj−xi+yj−yi
=
−
(
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),(xi−yi)−(xj−yj) 两种结果,取最大值即可。
所以维护每一个 x i + y i x_i+y_i xi+yi 和 x i − y i x_i-y_i xi−yi ,分别排序就可以了。
代码
#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