第三次训练赛题解

题目背景
998244353最优美的性质莫过于它是个完美恶臭数:
998244353=( 114514 * ( 54-1+114 * (1+145+1+4) ) ) + ( 4+11451 * (4-1-15+14) ) + ( 11+4154 + (141+541) ) + (4-1-15+14)
之所以称为完美,如果您仔细观察,您会发现每一个括号里114514都出现了正整数次!
今天,你需要用这个恶臭数进行一系列的复杂运算(或许?)
题目描述
米4达的替身名为"性感手枪",可以操纵子弹的飞行轨迹。一天在与"绯红之王"的战斗中米4达打光了子弹,所以他不得不重新装弹。他一次性掏出了N发子弹,编号从1到N,他需要从中选择M枚子弹。除此之外,他不会选择其中编号带有4的子弹,例如4号子弹,44号子弹,444号子弹。米4达一共有多少种选择子弹的方案
输入格式
第一行输入一个正整数T(1<=T<=1e5)表示数据组数
接下来输入一行2个正整数N和M(1<=N,M<=2000),含义如题
输出格式
输出T行,每行输出可选方案数
对于每个数据,答案对998244353取模后输出
输入输出样例
输入 #1复制
3
5 3
3 1
4 4
输出 #1复制
4
3
0

一道组合数学,所用的知识是高中学的。但要注意到的是本题的问询量很高(1e5次问询),如果对于每次问询都进行常规的组合计算会导致超时
这里注意到,如果a和b的范围较小,所以可以利用组合递推式先预处理出所有a,b的答案
由高中知识,有组合递推式:
请添加图片描述
用以下代码即可实现高效预处理:

for (int i = 0; i < N; i ++ )
		for (int j = 0; j <= i; j ++ )
			if (!j)
				c[i][j] = 1;
			else
				c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;

实现预处理
此外,还需要注意条件特判,如果可用子弹数小于所需子弹数,那么可选的方法就是0,此时应输出0
参考代码:

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2010, mod = 998244353;
int c[N][N];
int num[N];//i个子弹中实际可用的数量
bool check(int x) {
    
    
	while (x) {
    
    
		int k = x % 10;
		if (k == 4)
			return false;
		x /= 10;
	}
	return true;
}
void init() {
    
    
	num[0] = 0;
	for (int i = 1; i <= 2000; i++) {
    
    
		if (check(i)) {
    
    
			num[i] = num[i - 1] + 1;
		} else {
    
    
			num[i] = num[i - 1];
		}
	}
	for (int i = 0; i < N; i ++ )
		for (int j = 0; j <= i; j ++ )
			if (!j)
				c[i][j] = 1;
			else
				c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}


int main() {
    
    
	int n;
	init();
	scanf("%d", &n);
	while (n -- ) {
    
    
		int a, b;
		scanf("%d%d", &a, &b);
		a = num[a];
		if (a < b) {
    
    
			cout << "0" << endl;
			continue;
		}
		printf("%d\n", c[a][b]);
	}
	return 0;
}


题目描述
你是一个即将上任的电影导演,你刚刚发布了你的第一部电影。你还推出了一个简单的评论网站,有两个按钮可以按–好评和差评。
然而,该网站的内部并不那么简单。有两个服务器,每个服务器都有好评的和差评的计数。
评审员一个接一个地进入网站。每个评论者都是以下类型之一。
类型1:评论者已经看过电影,并且他们喜欢它–他们按下了好评的按钮。
类型2:评论者看了电影,他们不喜欢它–他们按下了差评按钮。
类型3:评论者没有看过电影–他们在他们所在的服务器上查看当前电影的好评和差评的数量,并决定按什么按钮。如果差评票数多于好评票数,那么评论者就会对电影进行差评。否则,他们就给电影好评。 每个评论员对电影投票一次。
由于你有两个服务器,你实际上可以操纵投票,使你的电影得到尽可能多的好评。当评论员进入一个网站时,你知道他们的类型,你可以把他们送到第一个服务器或第二个服务器。
如果你决定把每个评论者送到哪个服务器,你能在两个服务器上收集到的最大的好评总数是多少?
输入格式
第一行包含一个整数t(1≤t≤1e4)–测试案例的数量。
然后是对t个测试案例的描述。
每个测试案例的第一行包含一个整数n (1≤n≤50) - 评审员的数量。
每个测试案例的第二行包含n个整数r1,r2,…,rn (1≤ri≤3) - 评审员的类型,以他们进入网站的相同顺序。
输出格式
对于每个测试案例,打印一个整数–如果你决定将每个评论者送到哪个服务器,你可以在两个服务器上收集到的最大的支持票总数。
输入输出样例
输入 #1复制
4
1
2
3
1 2 3
5
1 1 1 1 1
3
3 3 2
输出 #1复制
0
2
5
2
说明/提示
在这个例子的第一个测试案例中,你可以把唯一的评论者送到任何一个服务器上–无论如何他们都会评分。这部电影不会收到任何加分。
在这个例子的第二个测试案例中,你可以把所有的评论者送到第一个服务器。
第一个评论者好评。 第二个审阅者差评。 最后一个审稿人看到差评的数量不超过好评的数量–给电影好评。 总共有两个加分项。另外,你可以把第一个和第二个评论员送到第一个服务器,把最后一个评论员送到第二个服务器。
第一个评论者在第一个服务器上好评。 第二位评论者在第一台服务器上差评。 最后一位评论者在第二台服务器上没有看到好评或差评–给电影好评。

思路:
根据题意可知,能给电影带来好评的评论员类型有1和3,真正能影响结果的只有3。所以我们只需要将类型1和类型3的人放在同一个服务器,将类型2的人放在另一个服务器。就能实现好评最大化。
参考代码

#include <bits/stdc++.h>
using namespace std;
int t, n, k;

int main() {
    
    
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin >> t;
	while (t--) {
    
    
		cin >> n;
		int ans = 0;
		for (int i = 1; i <= n; i++) {
    
    
			cin >> k;
			if (k == 1 || k == 3)
				ans++;
		}
		cout << ans << endl;
	}
}

题目描述
与运算(&)和或运算(|)拥有非常奇妙的性质
有一个未知的,长度为N数组A
两个已知的,长度为N-1的数组B和C 其中:
B[i]=A[i-1] & A[i]
C[i]=A[i-1] | A[i]
现在有一个未知的长度为N-1的数组D[i],其有:
D[i]=A[i-1]+A[i]
求出D[i],然后你还需要将D[i]除3后对114514取模后再对114514取模后输出
注:BCD的下标均从2开始,A的下标从1开始
注意:你不必要关心数据是否合法
输入格式
第一行为t,代表数据的组数
在每一组数据中:
第一行为N,代表A数组的长度
第二行有N-1个数,代表B数组的值
第三行有N-1个数,代表C数组的值
输出格式
输出t行,每行输出输出N-1个数,代表((D/3)%114514)%114514
输入输出样例
输入 #1复制
1
4
2 3 4
3 2 1
输出 #1复制
112513 112513 112513
说明/提示
注意区分整数取模和分数取模
t<=10
2<=N<=1e5
1<=ai,bi<=1e7
这道题涉及两个问题:与运算或运算的性质,以及分数取模
性质:a+b=a|b+a&b
由该性质可知,D数组其实就是B,C数组之和
得到D数组后还需要除3后对114514取模。
分数取模需要用到费马小定理:(费马小定理证明自行百度)
(若存在整数 a , p 且gcd(a,p)=1,即二者互为质数,则有a^(p-1)mod p≡ 1(mod p)
由于a^(p-1)=a^(p-2)*a
所以a^(p-2)*a mod p≡ 1 mod p
a^(p-2) mod p≡1/a mod p

两边同时乘上b
得:b/a mod p =b*a^(p-2) mod(p)
即: (b/a)%mod=b*pow(a,p-2);
由此即可得分数取模公式.
注意,分数取模公式不能用于整数取模,所以要对结果能被3整除的数据进行特判

参考代码

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
long long b[N], c[N], d[N];
long long mod = 114514;
int n;


long long qmi(long long a, long long k) {
    
    //快速幂
	long long ans = 1;
	while (k) {
    
    
		if (k & 1)
			ans = ans * a % mod;
		k >>= 1;//(k/=2)
		a = a * a % mod;
	}
	return ans;
}

int main() {
    
    

	int t;
	cin >> t;
	while (t--) {
    
    
		cin >> n ;
		for (int i = 2; i <= n; i++)
			cin >> b[i];
		for (int i = 2; i <= n; i++)
			cin >> c[i];
		for (int i = 2; i <= n; i++)
			d[i] = b[i] + c[i];
		for (int i = 2; i <= n; i++) {
    
    
			//(a/b)%mod=a*pow(b,mod-2);
			//d[i]/3%114514=d[i]*pow(3,114514-2)
			if (d[i] % 3 == 0) {
    
    
				cout << (d[i] / 3) % mod << " ";
			} else
				cout << d[i] *qmi(3, mod - 2) % mod << " ";
		}
		cout << endl;
	}
	return 0;

}

Guess you like

Origin blog.csdn.net/fdxgcw/article/details/119857297