前言
2023.6.16: 出成绩了,国一第15前排靠后,算是完成任务
先简单写写,数据范围可能有小错,等题面出来了再更新
2024.6.1:已更新体面,更新 I 题题解
A: 互质
本题总分:5分
【问题描述】
求出在 [ 1 , 202 3 2023 ] [1,2023^{2023}] [1,20232023]范围内,有多少个整数与 2023 2023 2023 互质,答案对 1 0 9 + 7 10^9+7 109+7取模。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
640720414
md考试时脑抽把
1
1
1 给减掉了,白白丢了
5
5
5 分。。
易得
2023
=
7
∗
17
∗
17
2023=7*17*17
2023=7∗17∗17,故可以先求出与2023不互质的数,然后总数减去即可。
设
a
a
a 为因数有7的数,
b
b
b 为因数有17的数,
c
c
c 为因数有7*17=119的数,显然不互质的数的总量为:
a
+
b
−
c
a+b-c
a+b−c.
static long fpow(long a,long b) {
long res = 1;
a%=mod;
while(b>0) {
if(b%2==1) res = res*a%mod;
a = a*a%mod;
b/=2;
}
return res;
}
static void solve() throws IOException{
long res=fpow(2023,2023);
long a = fpow(2023,2023)*fpow(7,mod-2)%mod;
long b = fpow(2023,2023)*fpow(17,mod-2)%mod;
long c = fpow(2023,2023)*fpow(7*17,mod-2)%mod;
res = (res-a-b +c+2*mod)%mod;
pw.println(res);
}
B: 逆元
本题总分:5分
【问题描述】
给定质数 M = 2146516019 M=2146516019 M=2146516019, 求出在 [ 1 , 233333333 ] [1,233333333] [1,233333333]内所有自然数的逆元。则所有逆元的异或和为多少?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
1307261675
快速幂暴力求逆元,逐个异或,比赛时跑了大概10多分钟
static long fpow(long a,long b) {
long res = 1;
a%=mod;
while(b>0) {
if(b%2==1) res = res*a%mod;
a = a*a%mod;
b/=2;
}
return res;
}
static void solve() throws IOException{
mod = 2146516019;
ans=0;
for(int i=1;i<=233333333;i++) {
long res = fpow(i,mod-2);
ans ^=res;
}
System.out.println(ans);
}
对于求解 1 , 2 , 3 , . . . , n 1,2,3,...,n 1,2,3,...,n 每个数的逆元,用快速幂或扩展欧几里得就很慢,有一种线性求逆元的方法:
这里给出递推式:
i
−
1
=
{
1
,
i
=
1
−
⌊
p
i
⌋
(
p
m
o
d
i
)
−
1
,
i
≠
1
(
m
o
d
p
)
i^{-1}= \begin{cases} 1, & i=1\\ -\lfloor {p \over i} \rfloor(p \space mod \space i)^{-1}, & i \not =1 \end{cases} (mod \space p)
i−1={1,−⌊ip⌋(p mod i)−1,i=1i=1(mod p)
推导:
显然
1
−
1
≡
1
(
m
o
d
p
)
1^{-1} \equiv 1 \space (mod \space p)
1−1≡1 (mod p)。
对于
i
−
1
i^{-1}
i−1,令
k
=
⌊
p
i
⌋
k=\lfloor {p \over i} \rfloor
k=⌊ip⌋,
j
=
p
m
o
d
i
j=p \space mod \space i
j=p mod i,有
p
=
k
i
+
j
p=ki+j
p=ki+j,即
k
i
+
j
≡
0
(
m
o
d
p
)
ki+j \equiv 0 \space(mod \space p)
ki+j≡0 (mod p);
两边同乘以
i
−
1
×
j
−
1
i^{-1} \times j^{-1}
i−1×j−1,化简得到
i
−
1
≡
−
k
j
−
1
(
m
o
d
p
)
i^{-1} \equiv -kj^{-1} \, (mod\,p)
i−1≡−kj−1(modp);
带入
j
=
p
m
o
d
i
j=p \space mod \space i
j=p mod i,又
p
=
k
i
+
j
p=ki+j
p=ki+j,有:
i
−
1
≡
−
⌊
p
i
⌋
(
p
m
o
d
i
)
−
1
(
m
o
d
p
)
i^{-1} \equiv -\lfloor {p\over i}\rfloor (p\space mod\space i)^{-1}\space (mod\space p)
i−1≡−⌊ip⌋(p mod i)−1 (mod p)
又
p
m
o
d
i
<
i
p\space mod \space i<i
p mod i<i,故可以迭代推出。
static void solve() throws IOException{
mod = 2146516019;
long inv[] = new long[233333335];
inv[1]=1;
ans=1;
for(int i=2;i<=233333333;i++) {
inv[i] = (long)(mod-mod/i)*inv[(int)(mod%i)]%mod;
ans ^=inv[i];
}
pw.println(ans);
}
C: 玩具
时间限制: 3.0 s 3.0 s 3.0s 内存限制: 512.0 M B 512.0 MB 512.0MB 本题总分: 10 10 10 分
【问题描述】
小明的妈妈给她买了 n n n 个玩具,但是为了同时考察他的智力,只给了他 2 ∗ n 2*n 2∗n 个玩具零件,第 i i i 个零件的重量为 w i ( 1 ≤ i ≤ 2 ∗ n ) w_i(1≤i≤2*n) wi(1≤i≤2∗n)。
其中任意两个零件都能拼接成一个玩具,这个玩具的权重等于这两个零件的重量的乘积。小明的妈妈希望小明能够使用这 2 ∗ n 2*n 2∗n 个零件拼接出 n n n 个玩具(每个零件必须使用且只能使用一次),使得所有玩具的权重的和最小。
小明希望你帮帮他计算出最小的权重和。
【输入格式】
第一行一个整数
n
n
n 。
第二行包含
2
n
2n
2n 个由空格隔开的整数
w
1
,
w
2
,
.
.
.
,
w
2
n
w_1,w_2,...,w_{2n}
w1,w2,...,w2n。
【输出格式】
一行整数,表示答案。
【样例输入】
2
2 2 3 4
【样例输出】
14
【提示】
对于 20% 的数据,
n
≤
1
0
3
n≤10^3
n≤103。
对于 100% 的数据,
1
≤
n
≤
1
0
5
,
0
≤
w
i
≤
1
0
5
1 ≤ n ≤ 10^5 , 0 ≤ w_i ≤ 10^5
1≤n≤105,0≤wi≤105。
排序,取最大和最小的乘积贡献到答案中即可。
这不沙比题么
import java.util.*;
import java.io.*;
public class Main {
static int n,m,mod=(int)998244353,maxn=200005,inf=(int)1e9;
static long ans=0,INF=(long)1e18;
public static void main(String[]args) throws IOException{
int T = 1;
while(T-->0) solve();
}
static Scanner sc = new Scanner (System.in);
static void solve() throws IOException{
n = sc.nextInt();
long a[] = new long[maxn];
for(int i=1;i<=n*2;i++) a[i] = sc.nextLong();
Arrays.sort(a,1,2*n+1);
for(int i=1,j=2*n;i<j;i++,j--) {
ans += a[i]*a[j];
}
System.out.println(ans);
}
}
D: 不完整的等式
时间限制: 3.0 s 3.0 s 3.0s 内存限制: 512.0 M B 512.0 MB 512.0MB 本题总分: 10 10 10 分
【问题描述】
给一个等式
A
A
A
o
p
op
op
B
=
C
B=C
B=C,其中
a
,
b
,
c
a,b,c
a,b,c都是非负整数,
o
p
op
op 为
{
+
,
−
,
∗
,
/
}
\{+,-,*,/\}
{+,−,∗,/} 四个中的一个。
a
,
b
,
c
,
o
p
a,b,c,op
a,b,c,op 四个中一个会被
?
?
? 代替,输出被代替的那个数或符号,保证有唯一解。
【输入格式】
输入一行字符串表示不完整的等式。
【输出格式】
输出被代替的那个数或符号。
【样例输入1】
1+?=2
【样例输出1】
1
【样例输入2】
10?3=3
【样例输出2】
/
【提示】
对于 20% 的数据,被擦掉的部分是
C
C
C。
对于 40% 的数据,被擦掉的数据是
o
p
op
op。
对于 100% 的数据,算式长度不超过10,不包含空格。算式中出现的整数不包含前导零。输入保证合法且有唯一解。
模拟,没什么好说的
import java.util.*;
import java.io.*;
public class Main {
static int n,m,mod=(int)998244353,maxn=200005,inf=(int)1e9;
static long ans=0,INF=(long)1e18;
static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
static StreamTokenizer st = new StreamTokenizer(bf);
static PrintWriter pw = new PrintWriter(System.out);
public static void main(String[]args) throws IOException{
int T = 1;
//T = Integer.parseInt(S());
while(T-->0) solve();
pw.flush();
}
static int I() throws IOException{
st.nextToken();
return (int)st.nval;
}
static long c1(long a,long b,char op) {
if(op=='+') return a+b;
if(op=='-') return a-b;
if(op=='*') return a*b;
return a/b;
}
static long c2(long a,long b,char op) {
if(op=='+') return a-b;
if(op=='-') return a+b;
if(op=='*') return a/b;
return b*a;
}
static long c3(long a,long b,char op) {
if(op=='+') return a-b;
if(op=='-') return a+b;
if(op=='*') return a/b;
return b/a;
}
static Scanner sc = new Scanner(System.in);
static void solve() throws IOException{
String s[] = sc.next().split("=");
if(s[1].equals("?")) {
long a=0,b=0;
char op = ' ';
int i=0;
for(;i<s[0].length();i++) {
char c = s[0].charAt(i);
if(c<'0' || c>'9') break;
a = a*10+(int)(c-'0');
}
op = s[0].charAt(i++);
for(;i<s[0].length();i++) {
char c = s[0].charAt(i);
b = b*10+(int)(c-'0');
}
pw.println(c1(a,b,op));
}
else {
if(s[0].charAt(0)=='?') {
long a=Long.parseLong(s[1]),b=0;
char op = ' ';
int i=1;
op = s[0].charAt(i++);
for(;i<s[0].length();i++) {
char c = s[0].charAt(i);
b = b*10+(int)(c-'0');
}
pw.println(c2(b,a,op));
}
else {
long a=0,b=0;
char op = ' ';
int i=0;
for(;i<s[0].length();i++) {
char c = s[0].charAt(i);
if(c<'0' || c>'9') break;
a = a*10+(int)(c-'0');
}
op = s[0].charAt(i++);
if(op=='?') {
for(;i<s[0].length();i++) {
char c = s[0].charAt(i);
b = b*10+(int)(c-'0');
}
long c = Long.parseLong(s[1]);
if(a+b==c) pw.println("+");
if(a*b==c) pw.println("*");
if(a/b==c) pw.println("/");
if(a-b==c) pw.println("-");
}
else {
b=Long.parseLong(s[1]);
pw.println(c3(b,a,op));
}
}
}
}
}
E: 星球
时间限制: 3.0 s 3.0 s 3.0s 内存限制: 512.0 M B 512.0 MB 512.0MB 本题总分: 15 15 15 分
【问题描述】
小明驾驶飞船对某星系发起攻击。星系中有 n n n 颗星球,编号依次是 1,2,3,…, n n n 。第 i i i 颗星球的坐标是 ( x i , y i , z i x_i,y_i,z_i xi,yi,zi),且其防御强度为 w i w_i wi。
小明需要规划出进攻这 n n n 颗星球的顺序使得其进攻所需能量最少。
对于一个遍历顺序 { p 1 , p 2 , . . . , p n } \{p_1,p_2,...,p_n\} {p1,p2,...,pn},小明进攻所需的能量为 E = ∑ i = 2 n d ( p i − 1 , p i ) ∗ w i E=\sum_{i=2}^n d(p_{i-1},p_i)*w_i E=∑i=2nd(pi−1,pi)∗wi,其中 d ( p i − 1 , p i ) d(p_{i-1},p_i) d(pi−1,pi) 表示 p i − 1 , p i p_{i-1},p_i pi−1,pi 两颗星球之间的直线距离。小明想知道进攻所需的最少能量是多少。
【输入格式】
第
1
1
1 行一个整数
n
n
n。
后面
n
n
n 行,每行给出四个整数
x
i
,
y
i
,
z
i
,
w
i
x_i,y_i,z_i,w_i
xi,yi,zi,wi。
【输出格式】
一个浮点数,保留两位有效数字。
【样例输入】
3
4 3 3 5
2 2 3 5
3 1 1 3
【样例输出】
18.53
【提示】
对于 20% 的评测用例,
N
≤
8
N ≤ 8
N≤8;
对于 100% 的评测用例,
N
≤
18
,
0
≤
x
i
,
y
i
,
z
i
,
w
i
<
=
100
N ≤ 18 , 0≤x_i,y_i,z_i,w_i<=100
N≤18,0≤xi,yi,zi,wi<=100。
旅行商问题变种。不了解的可以自行查询学习
在原旅行商问题中,有
n
n
n 个点。若起始点为
0
0
0,设
d
p
[
i
]
[
S
]
dp[i][S]
dp[i][S] 为从点
i
i
i 出发,经过点的集合为
S
S
S且都只经过一次,最终返回出发点
0
0
0 的最小花费。显然总集合数量为
2
n
2^n
2n 种。
这题可以虚设一个点
0
0
0 ,设点
0
0
0 到任何点距离都为
0
0
0,那么显然最终答案为
d
p
[
0
]
[
2
n
−
1
]
dp[0][2^n-1]
dp[0][2n−1].
时间复杂度: O ( n 2 ∗ 2 n ) O(n^2*2^{n}) O(n2∗2n)
import java.io.*;
import java.util.*;
public class Main{
static int maxn = 200005,n,m,inf=(int)2e9;
static long INF = (long)2e18,ans = 0,mod = (int)1e9+7;
static Scanner sc = new Scanner (System.in);
static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
static StreamTokenizer st =new StreamTokenizer(bf);
static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
public static void main(String[]args) throws IOException{
int T = 1;
while(T-->0) solve();
pw.flush();
}
static final int I() throws IOException {
st.nextToken();
return (int)st.nval;
}
static long[]w=new long[20];
static int []x = new int [20],y=new int [20],z=new int[20];
static double as=INF;
static double dis(int i,int j) {
if(i==0) return 0;
return Math.sqrt(Math.pow(x[i]-x[j], 2)+Math.pow(y[i]-y[j], 2)+Math.pow(z[i]-z[j], 2))*w[j];
}
static void solve() throws IOException{
n = I();
for(int i=1;i<=n;i++) {
x[i]=I();y[i]=I();z[i]=I();w[i] = I();
}
m = 1<<n; //集合数量
double dp[][] = new double[22][m];
for(int j=1;j<m;j++) {
for(int i=0;i<=n;i++) {
dp[i][j] = INF;
if((j>>(i-1))%2==1) continue; //集合有 i,跳过
for(int k=1;k<=n;k++) {
if((j>>(k-1))%2==0) continue;
if(dp[i][j] > dis(i,k) + dp[k][j^(1<<(k-1))])
dp[i][j] = dis(i,k) + dp[k][j^(1<<(k-1))];
}
}
}
pw.printf("%.2f",dp[0][m-1]);
}
}
F: 序列
时间限制: 3.0 s 3.0 s 3.0s 内存限制: 512.0 M B 512.0 MB 512.0MB 本题总分: 15 15 15 分
【问题描述】
给定一长为 n n n 的正整数序列 A 1 , A 2 , . . . , A n A_1,A_2,...,A_n A1,A2,...,An,同时有一个首项为 d d d,公差为 d d d,项数为 n n n 的等差数列 { b 1 = d , b 2 = 2 d , . . . , b n = n d } \{b_1=d,b_2=2d,...,b_n=nd\} {b1=d,b2=2d,...,bn=nd}。
定义 S d = ∑ a i ∣ b i 1 S_d=\sum_{a_i|b_i}1 Sd=∑ai∣bi1,即 S d S_d Sd 表示当公差为 d d d 时有多少对 ( a i , b i ) (a_i,b_i) (ai,bi) 满足 b i b_i bi 被 a i a_i ai 整除。
请求出 ∑ i = 1 n S i \sum_{i=1}^nS_i ∑i=1nSi。
【输入格式】
第一行一个整数
n
n
n;
第二行
n
n
n 个整数
A
1
,
A
2
,
.
.
,
A
n
A_1,A_2,..,A_n
A1,A2,..,An。
【输出格式】
一行整数,表示答案。
【样例输入】
4
2 2 3 1
【样例输出】
14
【样例说明】
当公差等于
1
1
1:
b
=
{
1
,
2
,
3
,
4
}
b=\{1,2,3,4\}
b={1,2,3,4},
S
1
=
3
S_1=3
S1=3。
当公差等于
2
2
2:
b
=
{
2
,
4
,
6
,
8
}
b=\{2,4,6,8\}
b={2,4,6,8},
S
2
=
4
S_2=4
S2=4。
当公差等于
3
3
3:
b
=
{
3
,
6
,
9
,
12
}
b=\{3,6,9,12\}
b={3,6,9,12},
S
3
=
3
S_3=3
S3=3。
当公差等于
4
4
4:
b
=
{
4
,
8
,
12
,
16
}
b=\{4,8,12,16\}
b={4,8,12,16},
S
4
=
4
S_4=4
S4=4。
所以答案为
3
+
4
+
3
+
4
=
14
3+4+3+4=14
3+4+3+4=14。
【提示】
对于 100% 的数据,
n
≤
1
0
3
n≤10^3
n≤103。
对于 100% 的数据,
1
≤
n
≤
1
0
5
,
1
≤
A
i
≤
n
1 ≤ n ≤ 10^5 , 1 ≤ A_i ≤ n
1≤n≤105,1≤Ai≤n。
考虑单独处理每个数。
设
x
=
d
∗
i
x=d*i
x=d∗i,显然
m
i
n
(
x
)
=
l
c
m
(
A
i
,
i
)
min(x)=lcm(A_i,i)
min(x)=lcm(Ai,i) ,则对答案的贡献为
i
∗
n
/
m
i
n
(
x
)
i*n/min(x)
i∗n/min(x)。
import java.io.*;
import java.util.*;
public class Main{
static int maxn = 200005,n,m,inf=(int)2e9;
static long INF = (long)2e18,ans = 0,mod = (int)1e9+7;
static Scanner sc = new Scanner (System.in);
static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
static StreamTokenizer st =new StreamTokenizer(bf);
static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
public static void main(String[]args) throws IOException{
int T = 1;
//T = I();
while(T-->0) solve();
pw.flush();
}
static final int I() throws IOException {
st.nextToken();
return (int)st.nval;
}
static int gcd(int a,int b) {
if(b==0) return a;
return gcd(b,a%b);
}
static long lcm(int a,int b) {
return 1L*a*b/gcd(a,b);
}
static void solve() throws IOException{
n = I();
for(int i=1;i<=n;i++) {
int a=I();
long x = lcm(a,i);
ans += (1L*n*i)/x;
}
pw.println(ans);
}
}
G: 电动车
时间限制: 1.0 s 1.0 s 1.0s 内存限制: 512.0 M B 512.0 MB 512.0MB 本题总分: 20 20 20 分
【问题描述】
有 n n n 个城市,由 m m m 条双向高速公路相连。其中第 i i i 条高速公路连接 u i u_i ui 号城市和 v i v_i vi 号城市,耗费 w i w_i wi 个单位的电量。
假设小蓝可以在出发城市,以及任何中途经过的城市里充满电。小蓝想知道,如何希望从任意城市开电动车到任意另一个城市,都可以找到一条由若干高速公路组成路径,使得不需要在任何高速公路内补充电量,那么这台电动车至少需要多少电量?
【输入格式】
第
1
1
1 行两个整数
N
,
M
N,M
N,M;
第
2
2
2 到
m
+
1
m+1
m+1 行,每行三个整数
u
i
,
v
i
,
w
i
u_i,v_i,w_i
ui,vi,wi。
【输出格式】
一行一个整数,表示答案。
如果存在两个城市不能相互到达,输出
−
1
-1
−1。
【样例输入】
4 5
1 2 3
1 3 5
2 4 2
4 3 2
4 1 4
【样例输出】
3
【样例说明】
从
1
1
1 到
2
2
2 可以走:
1
→
2
1 \rightarrow 2
1→2,至少需要电量
3
3
3。
从
1
1
1 到
3
3
3 可以走:
1
→
2
→
4
→
3
1 \rightarrow 2 \rightarrow 4 \rightarrow 3
1→2→4→3,至少需要电量
3
3
3。
从
1
1
1 到
4
4
4 可以走:
1
→
2
→
4
1 \rightarrow 2 \rightarrow 4
1→2→4,至少需要电量
3
3
3。
从
2
2
2 到
3
3
3 可以走:
2
→
4
→
3
2 \rightarrow 4 \rightarrow 3
2→4→3,至少需要电量
2
2
2。
从
2
2
2 到
4
4
4 可以走:
2
→
4
2 \rightarrow 4
2→4,至少需要电量
2
2
2。
从
3
3
3 到
4
4
4 可以走:
3
→
4
3 \rightarrow 4
3→4,至少需要电量
2
2
2。
综上所述,电动车至少需要 3 3 3 个单位的电量。
【提示】
对于 20% 的数据,
1
≤
N
,
M
≤
100
,
0
≤
w
i
≤
100
1 ≤ N,M ≤ 100, 0 ≤ w_i ≤ 100
1≤N,M≤100,0≤wi≤100。
对于 100% 的数据,
1
≤
N
,
M
≤
2
∗
1
0
5
,
,
0
≤
w
i
≤
1
0
9
1 ≤ N,M ≤ 2*10^5 ,, 0 ≤ w_i ≤ 10^9
1≤N,M≤2∗105,,0≤wi≤109。
板子题。
import java.io.*;
import java.util.*;
public class Main{
static int maxn = 200005,n,m,inf=(int)2e9;
static long INF = (long)2e18,ans = 0,mod = (int)1e9+7;
static Scanner sc = new Scanner (System.in);
static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
static StreamTokenizer st =new StreamTokenizer(bf);
static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
public static void main(String[]args) throws IOException{
int T = 1;
while(T-->0) solve();
pw.flush();
}
static final int I() throws IOException {
st.nextToken();
return (int)st.nval;
}
static class edge{
int u,v,w;
public edge(int a,int b,int c) {
u=a;v=b;w=c;
}
}
static int p[] = new int [maxn];
static int find(int x) {
if(p[x] == x) return x;
return p[x] = find(p[x]);
}
static Vector<edge> g = new Vector<>();
static void krus() {
Collections.sort(g,(o1,o2)->o1.w-o2.w);
int cnt=0;
for(edge x:g) {
int a=x.u,b=x.v,w=x.w;
int aa = find(a),bb = find(b);
if(aa!=bb) {
p[aa]=bb;
ans=w;
cnt++;
}
}
if(cnt!=n-1) pw.println(-1); //不连通
else pw.println(ans);
}
static void solve() throws IOException{
n = I();m=I();
for(int i=1;i<=n;i++) p[i] = i;
while(m-->0) {
g.add(new edge(I(),I(),I()));
}
krus();
}
}
H: 游戏
时间限制: 3.0 s 3.0 s 3.0s 内存限制: 512.0 M B 512.0 MB 512.0MB 本题总分: 20 20 20 分
【问题描述】
给定一个长度为 n n n 的数组 [ a 1 , a 2 , . . . , a n ] [a_1,a_2,...,a_n] [a1,a2,...,an],熊大均匀随机选取连续的一段长度为 k k k 的序列,取序列最大值为 P P P;熊二均匀随机选取连续一段长度为 k k k 的序列,取序列最小值为 Q Q Q 。
求 P − Q P-Q P−Q 的期望值。
【输入格式】
第一行两个整数
n
n
n,
k
k
k;
第二行
n
n
n 个整数
a
1
,
a
2
,
.
.
.
,
a
n
a_1,a_2,...,a_n
a1,a2,...,an;
【输出格式】
一个浮点数,表示期望,保留两位有效数字。
【样例输入】
3 2
1 2 3
【样例输出】
1.00
【样例说明】
一共四种情况:
熊大选
[
1
,
2
]
[1,2]
[1,2],
P
=
2
P=2
P=2;熊二选
[
1
,
2
]
[1,2]
[1,2],
Q
=
1
Q=1
Q=1,
P
−
Q
=
1
P-Q=1
P−Q=1。
熊大选
[
1
,
2
]
[1,2]
[1,2],
P
=
2
P=2
P=2;熊二选
[
2
,
3
]
[2,3]
[2,3],
Q
=
2
Q=2
Q=2,
P
−
Q
=
0
P-Q=0
P−Q=0。
熊大选
[
2
,
3
]
[2,3]
[2,3],
P
=
3
P=3
P=3;熊二选
[
1
,
2
]
[1,2]
[1,2],
Q
=
1
Q=1
Q=1,
P
−
Q
=
2
P-Q=2
P−Q=2。
熊大选
[
2
,
3
]
[2,3]
[2,3],
P
=
2
P=2
P=2;熊二选
[
2
,
3
]
[2,3]
[2,3],
Q
=
1
Q=1
Q=1,
P
−
Q
=
1
P-Q=1
P−Q=1。
所以答案为
(
1
+
0
+
2
+
1
)
/
4
=
1.00
(1+0+2+1)/4=1.00
(1+0+2+1)/4=1.00。
【提示】
对于 100% 的数据, 1 ≤ n ≤ 1 0 5 , 0 < a i ≤ 1 0 9 , 0 < k ≤ n 1 ≤ n ≤ 10^5,0<a_i≤10^9,0<k≤n 1≤n≤105,0<ai≤109,0<k≤n。
区间维护最大最小,线段树应该大概不会超时,(主要是单调队列求最值忘了
手玩一下,答案可以写成 A n s = c n t ∗ ( ∑ P − ∑ Q ) / ( c n t ∗ c n t ) = ( ∑ P − ∑ Q ) / c n t Ans={cnt*(\sum P - \sum Q) / (cnt*cnt)}=(\sum P - \sum Q)/cnt Ans=cnt∗(∑P−∑Q)/(cnt∗cnt)=(∑P−∑Q)/cnt。其中 c n t = n − k + 1 cnt=n-k+1 cnt=n−k+1 表示可以选择多少个不同区间, ∑ P \sum P ∑P 所有不同区间的最大值之和, ∑ Q \sum Q ∑Q 所有不同区间的最小值之和,那么答案显然。
P . S . P.S. P.S. 题面出来发现是 n ≤ 1 0 5 n≤10^5 n≤105,那线段树应该挺快,要是 n ≤ 2 ∗ 1 0 6 n≤2*10^6 n≤2∗106 稳妥起见还是写单调队列吧。。
import java.io.*;
import java.util.*;
import java.math.*;
public class Main{
static int maxn = 2000005,n,m,inf=(int)2e9;
static long INF = (long)2e18,ans = 0,mod = (int)1e9+7;
static Scanner sc = new Scanner (System.in);
static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
static StreamTokenizer st =new StreamTokenizer(bf);
static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
public static void main(String[]args) throws IOException{
int T = 1;
//T = I();
while(T-->0) solve();
pw.flush();
}
static final int I() throws IOException {
st.nextToken();
return (int)st.nval;
}
static int a[] = new int [maxn];
static int mi[] = new int [maxn<<2];
static int mx[] = new int [maxn<<2];
static void up(int i) {
mi[i] = Math.min(mi[i<<1], mi[i<<1|1]);
mx[i] = Math.max(mx[i<<1], mx[i<<1|1]);
}
static void build(int i,int l,int r) {
if(l==r) {
mx[i]=mi[i]=a[l];return;
}
int mid=(l+r)/2;
build(i<<1,l,mid);build(i<<1|1,mid+1,r);
up(i);
}
static int query_mi(int i,int l,int r,int ll,int rr) {
if(ll<=l && r<=rr) return mi[i];
int mid=(l+r)/2;
int res = inf;
if(mid >=ll) res = Math.min(res, query_mi(i<<1,l,mid,ll,rr));
if(mid+1 <= rr) res = Math.min(res, query_mi(i<<1|1,mid+1,r,ll,rr));
return res;
}
static int query_mx(int i,int l,int r,int ll,int rr) {
if(ll<=l && r<=rr) return mx[i];
int mid=(l+r)/2;
int res = 0;
if(mid >=ll) res = Math.max(res, query_mx(i<<1,l,mid,ll,rr));
if(mid+1 <= rr) res = Math.max(res, query_mx(i<<1|1,mid+1,r,ll,rr));
return res;
}
static void solve() throws IOException{
n = I();m=I();
for(int i=1;i<=n;i++) {
a[i]=I();
}
build(1,1,n);
long cnt=n-m+1;
double ans=0;
for(int i=1;i+m-1<=n;i++) {
int j = i+m-1;
ans += query_mx(1,1,n,i,j) - query_mi(1,1,n,i,j);
}
pw.printf("%.2f\n",ans/cnt);
}
}
I: 非对称二叉树
时间限制: 3.0 s 3.0 s 3.0s 内存限制: 512.0 M B 512.0 MB 512.0MB 本题总分: 25 25 25 分
【问题描述】
小明觉得不对称的东西有独特的美感。
对于一颗含有 n n n 个结点的二叉树,小明规定如果对于其中任意一个结点 i i i 都满足条件: m a x { h l i , h r i } ⩾ k ∗ m i n { h l i , h r i } max\{h_{l_i},h_{r_i}\}\geqslant k*min\{h_{l_i},h_{r_i}\} max{hli,hri}⩾k∗min{hli,hri},则此二叉树为一颗非对称二叉树。其中 l i , r i l_i,r_i li,ri 分别是 i i i 的左儿子和右儿子, h x h_x hx 表示以 x x x 为根的子树高度(如果结点 x x x 不存在视为高度等于 0 0 0)。
给定 n , k n,k n,k,计算有多少种非对称二叉树。
【输入格式】
输入共一行,两个整数 n , k n,k n,k。
【输出格式】
一行整数,表示答案。
【样例输入】
4 2
【样例输出】
12
【提示】
对于 20% 的数据,
n
≤
12
n≤12
n≤12。
对于 100% 的数据,
n
≤
35
,
1
≤
k
≤
n
n ≤ 35 , 1 ≤ k ≤ n
n≤35,1≤k≤n。
d p [ i ] [ j ] dp[i][j] dp[i][j] 表示含有 n n n 个结点且高度为 j j j 非对称二叉树数量。
有转移式:
d
p
[
i
]
[
m
a
x
{
h
l
i
,
h
r
i
}
+
1
]
=
∑
m
a
x
{
h
l
i
,
h
r
i
}
⩾
k
∗
m
i
n
{
h
l
i
,
h
r
i
}
d
p
[
l
c
n
t
]
[
h
l
i
]
∗
d
p
[
r
c
n
t
]
[
h
r
i
]
dp[i][max\{h_{l_i},h_{r_i}\}+1]=\sum_{max\{h_{l_i},h_{r_i}\}\geqslant k*min\{h_{l_i},h_{r_i}\}}dp[l_{cnt}][h_{l_i}]*dp[r_{cnt}][h_{r_i}]
dp[i][max{hli,hri}+1]=∑max{hli,hri}⩾k∗min{hli,hri}dp[lcnt][hli]∗dp[rcnt][hri]
其中,
l
c
n
t
,
r
c
n
t
l_{cnt},r_{cnt}
lcnt,rcnt 表示左、右子树的结点数量。
枚举 i , l c n t i,l_{cnt} i,lcnt,即可得到 r c n t r_{cnt} rcnt,再枚举 h l i , h r i h_{l_i},h_{r_i} hli,hri 即可转移。
复杂度: O ( n 4 ) O(n^4) O(n4)
import java.util.*;
import java.io.*;
import java.math.*;
public class Main {
static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in),65535);
static StreamTokenizer st = new StreamTokenizer(bf);
static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
static int n,m,maxn=200005,inf = 0x3f3f3f3f;
static long ans=0,mod=(int)1e9+7,INF=(long)2e18;
public static void main(String[]args) throws IOException{
new Task().main();
pw.flush();
}
static int I() throws IOException {
st.nextToken();
return (int)st.nval;
}
static class Task{
void main()throws IOException{
int t=1;
//t=I();
while(t-->0) solve();
}
long [][]dp = new long[44][44];
private void solve() throws IOException {
n=I();m=I();
dp[1][1]=1;
dp[0][0]=1;
for(int i=2;i<=n;i++) {
for(int j=0;j<i;j++) {
int k=i-j-1;
for(int h1=0;h1<=j;h1++) {
for(int h2=0;h2<=k;h2++) {
int mx = Math.max(h1, h2),mi = Math.min(h1, h2);
if(mx < 1L*m*mi) continue;
dp[i][mx+1] += dp[j][h1]*dp[k][h2];
}
}
}
}
for(int i=1;i<=n;i++) ans += dp[n][i];
pw.println(ans);
}
}
}
J: 数和游戏
时间限制: 3.0 s 3.0 s 3.0s 内存限制: 512.0 M B 512.0 MB 512.0MB 本题总分: 25 25 25 分
没思路,有时间再看吧
以上。