1110考试总结
1101 考试总结
T1
题目大意:
给定一个不小于2 的整数k ,按照如下方式生成一个无限长的序列S (下标从0 开始)。
-
初始时序列只有一个元素S0 = 0 。
-
对于 j = 1,2,...,k-1分别把当前序列的每个元素都加上 j ,得到新的k -1个序列。
-
把新的k -1个序列依次接在当前序列后面,得到一个长度为当前序列长度k 倍的序列。
-
把这个序列每一项都变成其除以k 之后的余数,并把这个序列作为新的当前序列。
-
执行无穷次操作 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;
}