我要是下次打ABC还不睡午觉就是↑↓
前排提示: D D D题经典再现
A . A. A.
题意:
c
o
d
e
:
code:
code:
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
const int N = 105;
int n,m,h,w;
int a[N];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(i>=2)
{
if(a[i]>a[1])
{
printf("%d",i);
return 0;
}
}
}
printf("-1");
return 0;
}
B . B. B.
题意:一个景点容量为 K K K个人,一共 N N N组人,每组人数 A i A_i Ai。现在让这 N N N组人一组一组去景点,如果已进入景点的总人数加上 A i Ai Ai个人后小于 K K K,那就让 A i A_i Ai个人加入景点中;如果已进入总人数加上 A i A_i Ai个人后大于 K K K,那就让“景点启动次数”加一,总人数清零,再让这 A i A_i Ai个人去景点,直到 N N N组人全部看完。注意第 N N N组进去后也要让总人数清零,“景点启动次数”加一。求景点启动总次数。
数据规模: N , K , A i < = 100 N,K,Ai<=100 N,K,Ai<=100
c o d e : code: code:
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
const int N = 105;
int n,m,h,w,k;
int a[N];
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int cnt=0;//当前景点中总的人数
int ans=0;
for(int i=1;i<=n;i++)
{
if(cnt+a[i]<=k)
{
cnt+=a[i];
}
else
{
cnt=a[i];
ans++;
}
}
printf("%d",ans+1);
return 0;
}
C . C. C.
题意:
数据规模: N < = 3 e 5 , A i < = 1 e 8 N<=3e5,A_i<=1e8 N<=3e5,Ai<=1e8
做法:
先看数据规模,
x
,
y
<
=
1
0
8
x,y<=10^8
x,y<=108保证了
(
x
+
y
)
(x+y)
(x+y)对
1
0
8
10^8
108取模的时候最多减一次
1
0
8
10^8
108或者一次也不减,换句话说,
f
(
x
,
y
)
=
{
x
+
y
x
+
y
<
1
0
8
x
+
y
−
1
0
8
x
+
y
>
=
1
0
8
f(x,y)=\begin{cases} x+y & x+y<10^8 \\ x+y-10^8 & x+y>=10^8\\ \end{cases}
f(x,y)={x+yx+y−108x+y<108x+y>=108
那么我们只需要先求
Σ
i
=
1
N
−
1
Σ
j
=
i
+
1
N
A
i
+
A
j
\Sigma_{i=1}^{N-1} \Sigma_{j=i+1}^{N} A_i+A_j
Σi=1N−1Σj=i+1NAi+Aj的值,再用这个值减去
n
u
m
∗
1
0
8
num*10^8
num∗108就是答案,其中
n
u
m
num
num表示在所有循环到的
f
(
A
i
,
A
j
)
f(A_i,A_j)
f(Ai,Aj)中
A
i
+
A
j
>
=
1
0
8
A_i+A_j>=10^8
Ai+Aj>=108的出现次数
分析一下这个式子,发现交换 A i A_i Ai的顺序对答案并不会产生影响,所以我们可以先升序排序。
再开双指针,一个
i
i
i来枚举
A
i
A_i
Ai,另一个枚举位置
j
j
j,使得
A
j
A_j
Aj及以后的
A
k
A_k
Ak都能让
(
A
i
+
A
k
)
>
=
1
0
8
(A_i+A_k)>=10^8
(Ai+Ak)>=108,这样每个
A
i
Ai
Ai对
n
u
m
num
num的贡献次数就是
(
n
−
j
+
1
)
(n-j+1)
(n−j+1),特别注意,如果
j
j
j在
i
i
i的前面,意味着
A
i
A_i
Ai之后的任何
A
x
A_x
Ax都使得
(
A
i
+
A
x
)
>
=
1
0
8
(A_i+A_x)>=10^8
(Ai+Ax)>=108成立,
A
i
A_i
Ai贡献次数为
(
n
−
(
i
+
1
)
+
1
)
(n-(i+1)+1)
(n−(i+1)+1),再注意,如果找不到
j
j
j,那么
A
i
A_i
Ai贡献次数为
0
0
0。
(大概讲清楚了吧,不过赛时代码写的比较乱)
c o d e : code: code:
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#define int long long
using namespace std;
const int N = 3e5+5;
const int mod = 1e8;
int n,m,h,w;
int a[N];
int b[N];
int sum[N];
int ans;
signed main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i];
ans=sum[n]*(n-1);
sort(a+1,a+1+n);
int head;
int flag=0;
for(int i=1;i<=n;i++)
{
if(a[i]+a[n]>=mod)
{
head=i;
flag=1;
break;
}
}
if(!flag)//任意两个A相加都比1e8小
{
printf("%lld",ans);
return 0;
}
int tail=n;
for(int i=head;i<=n;i++)
{
while(1)
{
if(a[i]+a[tail]>=mod) tail--;
else break;
}
tail++;
b[i]=tail;//b[i]代表第二个指针的位置,从b[i]往后的j都满足A_i+A_j>=1e8
}
for(int i=head;i<=n;i++)
{
if(b[i]<=i)
{
ans-=(n-i)*mod; continue;
}
ans-=(n-b[i]+1)*mod;
}
printf("%lld",ans);
return 0;
}
D . D. D.
题意:
数据规模: N < = 2 ∗ 1 0 5 , A i < = 1 0 9 N<=2*10^5,A_i<=10^9 N<=2∗105,Ai<=109
我感觉这个题比C还好想呢,不过我连WA七次也是挺逆天的
分析:
易知 f ( x , y ) = x ∗ 1 0 d i g i t ( y ) + y f(x,y)=x*10^{digit(y)}+y f(x,y)=x∗10digit(y)+y ,其中 d i g i t ( y ) digit(y) digit(y)表示y的位数。
【下文把 f f f前面那个数称作 x x x位置,,后边那个数称为 y y y位置,形如 f ( x , y ) f(x,y) f(x,y)】
考虑每一个 A i A_i Ai对答案的总贡献。由两部分组成,一部分是在 y y y位置的贡献,另一部分是在 x x x位置的贡献。
y y y位置贡献:在这一坨求和的过程中, A i A_i Ai出现在 y y y位置的次数如果是 s u m y sumy sumy,那么 A i A_i Ai在 y y y位置的所有贡献为 s u m y ∗ A i sumy*A_i sumy∗Ai。一眼丁真, s u m y = ( i − 1 ) sumy=(i-1) sumy=(i−1),看不出来可以把求和号拆开找规律。
x x x位置贡献: A i A_i Ai后边的每一个 A j A_j Aj都和 A i A_i Ai拼接且仅拼接了一次,那么显然
x 位置总贡献 = Σ j = i + 1 N A i ∗ 1 0 A j = A i ∗ Σ j = i + 1 N 1 0 A j x位置总贡献 = \Sigma_{j=i+1}^{N} A_i*10^{A_j} = A_i*\Sigma_{j=i+1}^{N} 10^{A_j} x位置总贡献=Σj=i+1NAi∗10Aj=Ai∗Σj=i+1N10Aj
后边这个东西( Σ j = i + 1 N 1 0 A j \Sigma_{j=i+1}^{N} 10^{A_j} Σj=i+1N10Aj)是个后缀和,这个题就做完了,接下来只需要把每个 A i A_i Ai在 x x x和 y y y位置的总贡献加起来就是答案。
c o d e : code: code:
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#define int long long
using namespace std;
const int N = 2e5+5;
const int mod = 998244353;
int n,m,h,w;
int a[N];
int suf[N];
int p[15];
int dit(int x)
{
int ans=0;
while(x)
{
x/=10;
ans++;
}
return ans;
}
//void check()
signed main()
{
scanf("%lld",&n);
p[1]=10;
for(int i=2;i<=10;i++) p[i]=p[i-1]*10;//预处理指数
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
int ans=0;
for(int i=n;i>=1;i--)
{
suf[i]=suf[i+1];
int nowdit=dit(a[i]);
suf[i]+=p[nowdit];
suf[i]%=mod;
ans+=suf[i+1]*a[i]%mod;
ans%=mod;
}
for(int i=1;i<=n;i++) ans+=a[i]*(i-1),ans%=mod;
printf("%lld",ans%mod);
return 0;
}