T1
Alice和Bob又双叒叕开始玩游戏了。
有一个包含
N
N
N 个正整数的序列,序列元素不大于
N
N
N 。紧接着,他们维护了一个可重集合
S
S
S ,包含序列中的前
P
P
P 个元素。Alice先手,二人轮流进行下面的一系列操作:
1)从集合
S
S
S 中拿走一个元素,加到玩家的总分上面;
2)将序列中的下一个数字(如果存在)添加到集合
S
S
S 中;
这意味着游戏开始时,当第一个数从集合
S
S
S 中取出后,将序列的第
P
+
1
P+1
P+1 项加入到集合
S
S
S 中,以此类推至集合
S
S
S 被取空为止。
假使二人都尽力使自己的总分最大,设游戏的结果为Alice的总分与Bob的总分之差,那么请你在给定序列和集合元素的情况下,输出游戏的结果。
题解
我们可以想到一个暴力,用堆维护集合中的数,每次取堆顶
可惜这样效率是
O
(
n
k
l
o
g
n
)
O(nklogn)
O(nklogn) 的,想想怎么优化使得效率变为
O
(
n
k
)
O(nk)
O(nk)
我们可以得到一开始的时候集合内的最大值
m
a
x
max
max ,然后设一个计数器记录每个数出现了多少次
然后再设刚放进来的数为
n
o
w
now
now ,那如果
n
o
w
now
now 为
0
0
0 的话我们可以取
m
a
x
max
max 并且扫计数器找出下一个
m
a
x
max
max
如果
n
o
w
now
now 不为
0
0
0 的话取出
n
o
w
now
now
然后更新
n
o
w
now
now 的话只需要把要放进来的数和
m
a
x
max
max 作比较就好了,
<
m
a
x
<max
<max 则清为
0
0
0
最后扫一遍计数器取出就可以了
T2
九条可怜在玩一个很好玩的策略游戏:Slay the Spire,一开始九条可怜的卡组里有
2
n
2n
2n 张牌,每张牌上都写着一个数字
w
i
w_i
wi ,一共有两种类型的牌,每种类型各
n
n
n 张:
攻击牌:打出后对对方造成等于牌上的数字的伤害。
强化牌:打出后,假设该强化牌上的数字为
x
x
x ,则其他剩下的攻击牌的数字都会乘上
x
x
x 。保证强化牌上的数字都大于
1
1
1 。
现在九条可怜会等概率随机从卡组中抽出
m
m
m 张牌,由于费用限制,九条可怜最多打出
k
k
k 张牌,假设九条可怜永远都会采取能造成最多伤害的策略,求她期望造成多少伤害。
假设答案为
a
n
s
ans
ans ,你只需要输出
(
a
n
s
×
(
2
n
)
!
m
!
(
2
n
−
m
)
!
)
 
m
o
d
 
998244353
(ans \times \frac{(2n)!}{m!(2n-m)!} ) \bmod 998244353
(ans×m!(2n−m)!(2n)!)mod998244353即可
题解
挺有趣的一道题
不难发现我们要尽量选择强化牌,因为强化牌上的数
>
1
>1
>1 ,
比如假设
a
<
b
a<b
a<b ,那么
a
+
b
<
a
×
2
a+b<a \times 2
a+b<a×2
而且我们肯定选择更大的数
所以我们现将强化牌和攻击牌排序
设
f
i
,
j
f_{i,j}
fi,j 表示打出i张强化牌,最后一张是原序列中的第
j
j
j 张的积的和
g
i
,
j
g_{i,j}
gi,j 表示打出i张攻击牌,最后一张是原序列中的第
j
j
j 张的和的和
可以得到转移式子:
f
i
,
j
=
w
j
×
∑
k
=
1
j
−
1
f
i
−
1
,
k
f_{i,j}=w_j \times \sum_{k=1}^{j-1} f_{i-1,k}
fi,j=wj×∑k=1j−1fi−1,k
g
i
,
j
=
w
j
×
C
j
−
1
i
−
1
+
∑
k
=
1
j
−
1
g
i
−
1
,
k
g_{i,j}=w_j \times C_{j-1}^{i-1} + \sum_{k=1}^{j-1} g_{i-1,k}
gi,j=wj×Cj−1i−1+∑k=1j−1gi−1,k
设
F
i
,
j
F_{i,j}
Fi,j 表示选出i张强化牌,最优地打出j张牌的贡献
G
i
,
j
G_{i,j}
Gi,j 表示选出i张攻击牌,最优地打出j张牌的贡献
F
i
,
j
=
∑
k
=
1
n
f
j
,
k
×
C
n
−
k
i
−
j
F_{i,j}=\sum_{k=1}^n f_{j,k} \times C_{n-k}^{i-j}
Fi,j=∑k=1nfj,k×Cn−ki−j
G
i
,
j
=
∑
k
=
1
n
g
j
,
k
×
C
n
−
k
i
−
j
G_{i,j}=\sum_{k=1}^n g_{j,k} \times C_{n-k}^{i-j}
Gi,j=∑k=1ngj,k×Cn−ki−j
最终答案为
∑
i
=
0
m
−
1
F
i
,
m
i
n
(
i
,
k
−
1
)
∗
G
m
−
i
,
m
a
x
(
k
−
i
,
1
)
\sum_{i=0}^{m-1} F_{i,min(i,k-1)}*G_{m-i,max(k-i,1)}
∑i=0m−1Fi,min(i,k−1)∗Gm−i,max(k−i,1)
效率
O
(
T
n
2
)
O(Tn^2)
O(Tn2)
T3
时光匆匆,转眼间又是一年省选季……
这是小 Q 同学第二次参加省队选拔赛。今年,小 Q 痛定思痛,不再冒险偷取试题,而是通过练习旧试题提升个人实力。可是旧试题太多了,小 Q 没日没夜地做题,却看不到前方的光明在哪里。
一天,因做题过度而疲惫入睡的小 Q 梦到自己在考场上遇到了一道好像做过的题目,却怎么也想不起曾经自己是怎么解决它的,直到醒来还心有余悸。
小 Q 眉头一皱,感觉事情不妙,于是他找到了你,希望你能教他解决这道题目。小 Q 依稀记得题目要计算如下表达式的值
(
∑
i
=
1
A
∑
j
=
1
B
∑
k
=
1
C
d
(
i
j
k
)
)
 
m
o
d
 
(
1
0
9
+
7
)
\Big(\sum_{i = 1}^{A}\sum_{j = 1}^{B}\sum_{k = 1}^{C} d(i j k) \Big) \bmod (10^9 + 7)
(∑i=1A∑j=1B∑k=1Cd(ijk))mod(109+7)
其中
d
(
i
j
k
)
d(i j k)
d(ijk) 表示
i
×
j
×
k
i\times j\times k
i×j×k 的约数个数。
题解
先化式子(太难了
∑
i
=
1
A
∑
j
=
1
B
∑
k
=
1
C
∑
x
∣
i
∑
y
∣
j
∑
z
∣
k
[
gcd
(
x
,
y
)
=
1
]
[
gcd
(
x
,
z
)
=
1
]
[
gcd
(
y
,
z
)
=
1
]
\sum_{i=1}^A\sum_{j=1}^B\sum_{k=1}^C\sum_{x|i}\sum_{y|j}\sum_{z|k}[\gcd(x,y)=1][\gcd(x,z)=1][\gcd(y,z)=1]
∑i=1A∑j=1B∑k=1C∑x∣i∑y∣j∑z∣k[gcd(x,y)=1][gcd(x,z)=1][gcd(y,z)=1]
∑
x
=
1
A
∑
y
=
1
B
∑
z
=
1
C
[
gcd
(
x
,
y
)
=
1
]
[
gcd
(
x
,
z
)
=
1
]
[
gcd
(
y
,
z
)
=
1
]
⌊
A
x
⌋
⌊
B
y
⌋
⌊
C
z
⌋
\sum_{x=1}^A\sum_{y=1}^B\sum_{z=1}^C[\gcd(x,y)=1][\gcd(x,z)=1][\gcd(y,z)=1]⌊\frac{A}{x}⌋⌊\frac{B}{y}⌋⌊\frac{C}{z}⌋
∑x=1A∑y=1B∑z=1C[gcd(x,y)=1][gcd(x,z)=1][gcd(y,z)=1]⌊xA⌋⌊yB⌋⌊zC⌋
∑
x
=
1
A
∑
y
=
1
B
∑
z
=
1
C
∑
i
∣
x
,
i
∣
y
μ
(
i
)
∑
j
∣
x
,
j
∣
z
μ
(
j
)
∑
k
∣
y
,
k
∣
z
μ
(
k
)
⌊
A
x
⌋
⌊
B
y
⌋
⌊
C
z
⌋
\sum_{x=1}^A\sum_{y=1}^B\sum_{z=1}^C\sum_{i|x,i|y}\mu(i)\sum_{j|x,j|z}\mu(j)\sum_{k|y,k|z}\mu(k)⌊\frac{A}{x}⌋⌊\frac{B}{y}⌋⌊\frac{C}{z}⌋
∑x=1A∑y=1B∑z=1C∑i∣x,i∣yμ(i)∑j∣x,j∣zμ(j)∑k∣y,k∣zμ(k)⌊xA⌋⌊yB⌋⌊zC⌋
∑
i
=
1
A
∑
j
=
1
B
∑
k
=
1
C
μ
(
i
)
μ
(
j
)
μ
(
k
)
∑
i
∣
x
,
j
∣
x
⌊
A
x
⌋
∑
i
∣
y
,
k
∣
y
⌊
B
y
⌋
∑
j
∣
z
,
k
∣
z
⌊
C
z
⌋
\sum_{i=1}^A\sum_{j=1}^B\sum_{k=1}^C\mu(i)\mu(j)\mu(k)\sum_{i|x,j|x}⌊\frac{A}{x}⌋\sum_{i|y,k|y}⌊\frac{B}{y}⌋\sum_{j|z,k|z}⌊\frac{C}{z}⌋
∑i=1A∑j=1B∑k=1Cμ(i)μ(j)μ(k)∑i∣x,j∣x⌊xA⌋∑i∣y,k∣y⌊yB⌋∑j∣z,k∣z⌊zC⌋
对于下去整的东西我们可以
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn) 进行预处理
f
A
(
i
)
=
∑
i
∣
d
⌊
A
d
⌋
f_A(i)=\sum_{i|d}⌊\frac{A}{d}⌋
fA(i)=∑i∣d⌊dA⌋ (
B
,
C
B,C
B,C 同理
我们考虑如何计算答案
可以发现我们考虑枚举两个数,如果它们的
l
c
m
≤
m
a
x
(
a
,
b
,
c
)
lcm \leq max(a,b,c)
lcm≤max(a,b,c) 则相互连边,则对答案有贡献的就是图中的三元环了(考虑优化
先单独计算三个数相同的情况和三个数中有两个相同的情况
然后后者再两两连边,找出图中的三元环,然后计算答案
献上代码(参考了下网上别的题解
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1e5+5,P=1e9+7;
LL ans,fa[N],fb[N],fc[N];
int T,p[N],mu[N],tp,A,B,C,ce,sa[N];
int sb[N],sc[N],d[N],n;bool vis[N];
struct E{int u,v,w;}e[N<<4];
vector<pair<int,int> >g[N];
int main(){
mu[1]=1;for (int i=2;i<N;i++){
if (!vis[i]) p[++tp]=i,mu[i]=-1;
for (int j=1;j<=tp && p[j]*i<N;j++){
vis[p[j]*i]=1;
if (i%p[j]) mu[p[j]*i]=-mu[i];
else break;
}
}
for (scanf("%d",&T);T--;){
scanf("%d%d%d",&A,&B,&C);n=max(max(A,B),C);
for (int i=1;i<=n;i++)
for (int j=i;j<=n;j+=i)
fa[i]+=A/j,fb[i]+=B/j,fc[i]+=C/j;
// calc fd(y)=sigma_y|x d/x
for (int i=1;i<=n;i++) if (mu[i])
ans+=mu[i]*mu[i]*mu[i]*fa[i]*fb[i]*fc[i];
// calc three same
for (int i=1;i<=n;i++) for (int j=1;i*j<=n;j++)
if (mu[i*j]) for (int k=j+1;1ll*i*j*k<=n;k++)
if (mu[i*k] && __gcd(j,k)==1){
int x=i*j,y=i*k,z=x*k;d[x]++;d[y]++;e[++ce]=(E){x,y,z};
ans+=mu[x]*mu[x]*mu[y]*(fa[x]*fb[z]*fc[z]+fa[z]*fb[x]*fc[z]+fa[z]*fb[z]*fc[x]);
ans+=mu[x]*mu[y]*mu[y]*(fa[y]*fb[z]*fc[z]+fa[z]*fb[y]*fc[z]+fa[z]*fb[z]*fc[y]);
}
// calc two same and link
#define u e[i].u
#define v e[i].v
for (int i=1;i<=ce;i++){
if (d[u]>d[v] || (d[u]==d[v] && u>v))
swap(u,v);g[u].push_back(make_pair(v,e[i].w));
}
#define F first
#define S second
for (int i=1;i<=n;i++){
for (int j=g[i].size()-1;~j;j--){
int x=g[i][j].F,y=g[i][j].S;
sa[x]=fa[y];sb[x]=fb[y];sc[x]=fc[y];
}
for (int j=g[i].size()-1;~j;j--){
int x=g[i][j].F,y=g[i][j].S;
for (int k=g[x].size()-1;~k;k--){
int a=g[x][k].F,b=g[x][k].S,t=mu[i]*mu[x]*mu[a];
ans+=t*fa[y]*fb[b]*sc[a];ans+=t*fa[y]*sb[a]*fc[b];
ans+=t*sa[a]*fb[y]*fc[b];ans+=t*fa[b]*fb[y]*sc[a];
ans+=t*sa[a]*fb[b]*fc[y];ans+=t*fa[b]*sb[a]*fc[y];
}
}
#define y g[i][j].F
for (int j=g[i].size()-1;~j;j--) sa[y]=sb[y]=sc[y]=0;
}
printf("%lld\n",ans%P);ans=ce=0;
for (int i=1;i<=n;i++) d[i]=fa[i]=fb[i]=fc[i]=0,g[i].clear();
}
return 0;
}