20190228

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 作比较就好了, &lt; m a x &lt;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 ) ! ) &VeryThinSpace; m o d &VeryThinSpace; 998244353 (ans \times \frac{(2n)!}{m!(2n-m)!} ) \bmod 998244353 (ans×m!(2nm)!(2n)!)mod998244353即可

题解

挺有趣的一道题
不难发现我们要尽量选择强化牌,因为强化牌上的数 &gt; 1 &gt;1 >1
比如假设 a &lt; b a&lt;b a<b ,那么 a + b &lt; a × 2 a+b&lt;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=1j1fi1,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×Cj1i1+k=1j1gi1,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×Cnkij
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×Cnkij
最终答案为 ∑ 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=0m1Fi,min(i,k1)Gmi,max(ki,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 ) ) &VeryThinSpace; m o d &VeryThinSpace; ( 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=1Aj=1Bk=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=1Aj=1Bk=1Cxiyjzk[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=1Ay=1Bz=1C[gcd(x,y)=1][gcd(x,z)=1][gcd(y,z)=1]xAyBzC
∑ 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=1Ay=1Bz=1Cix,iyμ(i)jx,jzμ(j)ky,kzμ(k)xAyBzC
∑ 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=1Aj=1Bk=1Cμ(i)μ(j)μ(k)ix,jxxAiy,kyyBjz,kzzC
对于下去整的东西我们可以 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)=iddA ( B , C B,C B,C 同理
我们考虑如何计算答案
可以发现我们考虑枚举两个数,如果它们的 l c m ≤ m a x ( a , b , c ) lcm \leq max(a,b,c) lcmmax(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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值