1110考试总结

1101 考试总结

T1

​ 题目大意:

​ 给定一个不小于2 的整数k ,按照如下方式生成一个无限长的序列S (下标从0 开始)。

  1. 初始时序列只有一个元素S0 = 0 。

  2. 对于 j = 1,2,...,k-1分别把当前序列的每个元素都加上 j ,得到新的k -1个序列。

  3. 把新的k -1个序列依次接在当前序列后面,得到一个长度为当前序列长度k 倍的序列。

  4. 把这个序列每一项都变成其除以k 之后的余数,并把这个序列作为新的当前序列。

  5. 执行无穷次操作 2-4。

​ 例如k = 3 ,每一轮执行之后的序列分别是:

012

012 120 201

012120201 120201012 201012120

......

例如k = 2 ,则序列是 01101001100101101001011001101001……

现在给定整数 L, R ,你需要求\(\displaystyle \sum _{i = L} ^{R} h(i) * S_i\)的值,并输出答案对\(2^{32}\) 取模. \(h(i) = \lfloor \frac{(i \% 20000116) ^ 2 + i + 804}{233} \rfloor\).

\(T <= 100, 2 <= k <= 1000, L,R <= 1e16, \sum R - L <= 1e8\).

思维题.

我们不考虑模数, 当\(k = 3\)时候的序列应该就是:0 1 2 1 2 3 2 3 4 ...

然后我们考虑每个数是怎么来的, 我们把序列分层:

0
0 1 2
012 123 234

最后那个4其实是由上一层的2加上2得到的. 可以发现, 每一层的数字可以分层\(k\)块, 假设一个数字在第\(t\)块, 那么它就是由上一层对应数字加上\(t - 1\)得到的.

然后我们只需要找到这个数字对应的第\(t\)块是什么就好了.代码里的\(tmp[i]\)数组就是表示从第i层向第\(i + 1\)层需要加多少.

我们先求出\(l\)\(tmp\)数组, 然后推出\(l + 1\)\(tmp\)数组是什么.

怎么推呢?看代码里的\(inc\)函数.

首先从\(tmp[0] ++\), 如果说\(tmp[0] == k\),说明这一层不能继续加了, 就类似于进位一样, 让\(tmp[0] = 0, tmp[1] ++\).

好吧我还不透彻

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
	long long s = 0, f = 1; char ch;
	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
	for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
	return s * f;
}

int k, s, cnt, tmp[105];
unsigned ans; //开unsigned自动溢出,就不用取模了
long long l, r;

unsigned h(long long x) {
	long long t = x % 20000116;
	return (t * t + x + 804) / 233;
}
	
void inc() {
	tmp[0] ++; if(++ s == k) s = 0;
	for(int i = 0;tmp[i] == k; i++) {
		tmp[i] = 0; tmp[i + 1] ++;
		if(++ s == k) s = 0;
	}
}

int main() {

	for(int T = read(); T ; T --) {
		k = read(); l = read(); r = read(); ans = 0; cnt = 0;
		memset(tmp, 0, sizeof(tmp));
		for(long long i = l; i ; i /= k) tmp[cnt ++] = i % k;
		s = 0; for(int i = 0;i < cnt; i++) (s += tmp[i]) %= k;
		for(long long i = l;i <= r; i++, inc()) ans += h(i) * s;
		printf("%u\n", ans);
	}
	
	return 0;
}

/*
10
2 1 10 
3 1 10 
4 1 10 
5 1 10 
2 1001 5005 
10 123 456 
233 1024 6174 
16 10000 20000 
20 12345678 23456789 
987 2333123456789 2333198765432
*/

T4

(另一套题的T1)

​ 题目大意:

​ 给定一个\(n * m\)的棋盘, 然后放两个国际象棋的皇后, 问有多少种方案可以使两个皇后冲突.\(n, m <= 1e9\),答案对100000007取模.

题目链接

​ 数学, 组合数.

​ 对于每一行, 我们可以放的方案数是\(n * A_{m}^{2} = n *m * (m - 1)\), 对于每一列, 我们可以放的方案数是\(m * A_{n}^{2} = m * n * (n - 1)\).

​ 对于每一斜列, 我们可以....???有点难搞.

​ 每条斜线的长度不一样, 我们可以把大的式子写出来\(2 * (A_2^2 + A_3^2 + A_4^2+...+ A_n^2 * (m - n + 1) + ... + A_3^2 + A_2^2)\).(\(m >= n\), 乘二是因为有左斜线和右斜线)

​ 然后我们把括号拆一下:\(4 * (1 * 2 + 2 * 3 + 3 * 4 + ... + (n - 1) * n) + 2n(n - 1)(m - n) = \displaystyle 4 *\sum_{i = 1}^{n - 1} i(i + 1) + 2n(n - 1)(m - n) = 4 * (\sum_{i = 1}^{n - 1}i^2 + \sum_{i = 1}^{n - 1}i) + 2n(n - 1)(m - n)\).

\(\displaystyle \sum_{i = 1}^{n - 1}i = \frac{n(n - 1)}{2}\).这个很好理解.那前面那个死个妈怎么搞??

​ 首先:\(n ^ 3 - (n - 1)^3 = 3n^2 - 3n + 1, (n - 1)^3 - (n - 2)^3 = 3(n - 1)^2 - 3(n - 1) + 1\),这个应该很好推.

​ 然后:\(\displaystyle \sum_{i = 2}^{n} i^3 - (i - 1)^3 = n ^ 3 - 1^3 = 3(n ^ 2 + (n - 1)^2 + ... + 2^2 + 1^2) - 3(n + n - 1 + n - 2 + ... + 2 + 1) + (n - 1)\)(注意是\(n - 1\)).

​ 接着移项:\(3 * \displaystyle \sum_{i = 1}^{n} i^2 = n^3 - n + \frac{3n(n + 1)}{2}\), 所以\(\displaystyle \sum_{i = 1}^{n} i^2 = (n^3 - n + \frac{3n(n + 1)}{2})/3\) = \(\frac{2n^3 + 3n^2 + n}{6} = \frac{n(n - 1)(2n + 1)}{6}\).

​ 所以最后总的式子就是:\(n * m * (n - 1 + m - 1) + 2 * n * (n - 1) * (3 * m - n - 1) / 3\)

#include <bits/stdc++.h>

using namespace std;

const int mod = 100000007;
long long n, m, inv3;

int ksm(int x, int y) {
	int res = 1;
	for( ; y ; y >>= 1, x = 1ll * x * x % mod) if(y & 1) res = 1ll * res * x % mod; return res;
}

int main() {

	cin >> n >> m; inv3 = ksm(3, mod - 2);
	if(n > m) swap(n, m); 
	printf("%d", (n % mod * m % mod * (n - 1 + m - 1) % mod + 2 * n * (n - 1) % mod * (3 * m - n - 1) % mod * inv3 % mod) % mod);
	
	return 0;
}

posted @ 2020-11-10 20:10  C锥  阅读(125)  评论(0编辑  收藏  举报