Candies and Shops题解

Candies and Shops

写在前面

很抱歉 T3 赛时出锅了。这个悲惨的故事告诉我们一定要验题!!!

因为std出锅了,所以博客和视频讲解也出了一些问题。我会在下文中用加粗的括号来注明更改。给大家带来不便深表歉意。

题目分析

Part 1

首先,它告诉你要选择三家糖果店 \((x,y,z)\) 满足一些条件。我们先一条条分析。

  • \(x \leq z\)

这其实就是排了个序。

  • \(z = 3y + x\)

稍微整理一下,变成 \(z - x = 3y\),也就是说 \(3 | z - x\),也就是说 \(x \equiv z \ (\bmod 3)\)(这里有更改)

到这里,其实我们发现这第二个奇怪的式子其实就是个幌子,目的就是为了告诉你 \(x\)\(z\)\(3\) 同余。

(但是,因为 \(y\)\(1\) 开始,所以 \(x \not= z\),否则 \(y = 0\)

  • \(col_x = col_z\)

要求 \(x\)\(z\) 的颜色相同,那么,我们可以将同样颜色糖果店按照编号模 \(3\) 的余数分为三类,我们只需要选择余数相同的糖果店,就可以满足所有要求(对,其实 \(y\) 压根没用)。

那么,我们已经找到了符合题意的所有三元组,该如何统计答案呢?这就是下一个部分了。

PS:Part 2中的三元组指的都是按照上文的分类要求(颜色、模 \(3\) 余数)分类过后的三元组。

Part 2

我们先看一下每个三元组对答案的贡献:\((x + y)(col_x + col_y)(w_x + w_y)\)。看起来好像没什么头绪,于是,我们可以先举个例子算一算。不妨假设有 \(3\) 家糖果店 \(x,y,z\) 符合 Part 1中分析出的要求。

(下文有更改)

那么对答案的贡献就是:

\[(x + y)(col_x + col_y)(w_x + w_y) + (y + z)(col_y + col_z)(w_y + w_z) + (z + x)(col_z + col_x)(w_z + w_x) \]

因为他们的颜色都相同,不妨直接记成 \(c\)

\[2c(x + y)(w_x + w_y) + 2c(y + z)(w_y + w_z) + 2c(z + x)(w_z + w_x) \]

\[2c(xw_x+xw_y+yw_x+yw_y+yw_y+yw_z+zw_y+zw_z+zw_z+zw_x+xw_z+xw_x) \]

\[2c(x(2w_x+w_y+w_z)+y(w_x+2w_y+w_z)+z(w_x+w_y+2w_z)) \]

多举几个例子,我们发现,一般地,对于 \(n\) 家符合 Part 1要求的糖果店,其贡献为:

\(2c(a_1((n-1)w_1+w_2+...+w_n)+a_2(w_1+(n-1)w_2+...+w_n)+...+a_n(w_1+w_2+...+(n-1)w_n))\)

(上文有更改)

这样的话,我们只需要对于每种颜色模 \(3\) 的每种余数,预处理 \(w_1+w_2+...w_n\) 的结果,就可以 \(O(n)\) 统计答案,具体可参见下方代码。

细节问题

  • \(998244353\) 取模。

  • 由于中间计算过程中连乘了很多项,为了保险起见,可适当在某些乘号再取模一次,以免爆 int。

代码

(代码有更改)

#define MOD 998244353
#define MAXN 100000
#define MAXC 100000
#define MAXW 100000//大可不必管这些 

#include <cstdio>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

inline long long read(){
	long long t = 0,flag = 1;
	register char c = getchar();
	while (c < 48 || c > 57) {if (c == '-') flag = -1;c = getchar();}
	while (c >= 48 && c <= 57) t = (t << 1) + (t << 3) + (c ^ 48),c = getchar();
	return flag * t;
}//快读,可忽略。a = read() 可以认为等价于 cin >> a 

long long n,m,ans,col[MAXN],w[MAXN],sum[MAXC][3],tot[MAXC][3];

int main(){
	n = read(),m = read();//读入,可以认为等价于 cin >> n >> m; 
	for (int i = 1;i <= n;i++){
		col[i] = read(),w[i] = read();
		sum[col[i]][i % 3] += w[i];//统计 w[i] 之和
		++tot[col[i]][i % 3];//统计每类的个数 
		sum[col[i]][i % 3] %= MOD;
		tot[col[i]][i % 3] %= MOD;
	}
	for (int i = 1;i <= n;i++){
		ans = (ans + 2 * col[i] % MOD * (i * (sum[col[i]][i % 3] % MOD + (tot[col[i]][i % 3] - 2) % MOD * w[i] % MOD)) % MOD) % MOD;//那行统计答案的式子,略有改动 
	}
	printf("%lld\n",ans % MOD);
	return 0;
}
posted @ 2020-10-28 21:58  PYD1  阅读(110)  评论(0)    收藏  举报