#查找某篇题解:ctrl+f
#1 .51nod 1011
代码:
int gcd(a, b){
return b ? gcd(b, a%b) : a;
}
#2 .51nod 1135
代码:
#include
#include
#include
#include
#define mem(a,b) memset(a, b, sizeof(a))
#define LL long long
using namespace std;
const int maxn = 1000005;
int yue[maxn], tot, cnt;
int v[maxn], prime[maxn];
void is_prime(){
mem(v,1);
for(int i = 2; i <= maxn; i++){
if(v[i]){
prime[++cnt] = i;
for(int j = i; j <= maxn; j += i){
v[j] = 0;
}
}
}
}
void div(int x){
tot = 0;
int t = (int)sqrt(1.0*x);
for(int i = 1; prime[i] <= t; i++){
if(x % prime[i] == 0){
yue[++tot] = prime[i];
while(x % prime[i] == 0) x /= prime[i];
}
}
if(x > 1)
yue[++tot] = x;
}
LL Pow(LL a, LL b, LL m){
LL ans = 1;
a %= m;
while(b){
if(b & 1)
ans = ans * a % m;
a = a * a % m;
b >>= 1;
}
return ans;
}
int main(){
int p;
is_prime();
while(scanf("%d", &p) == 1 && p){
div(p-1);
for(int i = 2; i <= p-1; i++){
bool flag = 1;
for(int j = 1; j <= tot; j++){
int t = (p-1)/yue[j];
if(Pow((LL)i, (LL)t, (LL)p) == 1){
flag = 0;
break;
}
}
if(flag){
printf("%d\n", i);
break;
}
}
}
return 0;
}
#3 .51nod 1046
代码:
#include
#include
#include
#include
#include
#define LL long long
using namespace std;
LL Pow(LL a, LL b, LL p){
LL ans = 1LL;
a %= p;
while(b){
if(b & 1)
ans = ans * a % p;
a = a * a % p;
b >>= 1;
}
return ans;
}
int main(){
LL a, b, c;
scanf("%lld%lld%lld", &a, &b, &c);
printf("%lld\n", Pow(a, b, c));
return 0;
}
#4. 51nod 1073
代码:
#include
using namespace std;
int main(){
int n, k;
cin>>n>>k;
int s = 0;
for(int i = 1; i <= n; i++){
s = (s + k) % i;
}
cout<
#5. 51nod 1256
代码:
#include
#include
#include
#include
#include
#define LL long long
using namespace std;
void exgcd(LL a, LL b, LL &x, LL &y){
if(b == 0){
x = 1, y = 0;
return;
}
exgcd(b, a%b, x, y);
LL tmp = x;
x = y;
y = tmp - y * (a / b);
}
int main(){
LL a, b, x, y;
scanf("%lld%lld", &a, &b);
exgcd(a, b, x, y);
x = (x % b + b) % b;
printf("%lld\n",x);
return 0;
}
#6. 51nod 1136
代码:
#include
#include
using namespace std;
int phi(int n){
int ans = n;
for(int i = 2; i <= sqrt(n); i++){
if(n % i == 0){
ans = ans / i * (i-1);
while(n % i == 0) n /= i;
}
}
if(n > 1) ans = ans / n * (n-1);
return ans;
}
int main(){
int n;
cin>>n;
cout<
#7 .51nod 1079
代码:
#include
#include
#include
#define LL long long
LL exgcd(LL a, LL b, LL &x, LL &y){
if(!b){
x = 1, y = 0;
return a;
}
int d = exgcd(b, a%b, x, y);
int tmp = x;
x = y;
y = tmp - (a/b)*y;
return d;
}
LL CSD(int m[], int a[], int n){
LL x = 0, y, d;
LL M = 1;
LL ans = 0;
for(int i = 1; i <= n; i++){
M *= m[i];
}
for(int i = 1; i <= n; i++){
LL Mi = M / m[i];
d = exgcd(Mi, m[i], x, y);
x = x/d;
ans = (ans + a[i]*Mi*x) % M;
}
return (ans + M) % M;
}
int main(){
int n, m[15], a[15];
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d %d", &m[i], &a[i]);
}
printf("%lld\n", CSD(m, a, n));
return 0;
}
#8. 51nod 1240
##莫比乌斯(mobius)函数
代码:
//求单个数的mobius值
#include
#include
#include
using namespace std;
int c[1000005];
int main(){
int n, ans = 0, m = 0;
scanf("%d", &n);
int nn = n;
for(int i = 2; i <= sqrt(nn); i++){
if(n % i == 0){
c[++m] = 0;
while(n % i == 0){
n /= i;
c[m]++;
}
}
}
if(n > 1){
c[++m] = 1;
}
for(int i = 1; i <= m; i++){
if(c[i] >= 2){
printf("0\n");
return 0;
}
}
if(m & 1){
printf("-1\n");
}
else{
printf("1\n");
}
return 0;
}
//求2到n的mobius值
#include
#include
#include
using namespace std;
int miu[1000005];
int v[1000005];
int n;
int main(){
scanf("%d", &n);
for(int i = 2; i <= n; i++) miu[i] = 1, v[i] = 0;
for(int i = 2; i <= n; i++){
if(v[i]) continue;
miu[i] = -1;
for(int j = 2*i; j <= n; j += i){
v[j] = 1;
if( (j / i) % i == 0 ) miu[j] = 0;
else miu[j] *= -1;
}
}
for(int i = 2; i <= n; i++){
printf("%d ", miu[i]);
}
return 0;
}
#9. 51nod 1106
#include
#include
#include
using namespace std;
int n, t;
bool is_prime(int x){
for(int i = 2; i <= sqrt(x); i++){
if(x % i == 0){
return false;
}
}
return true;
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d", &t);
if(is_prime(t))
printf("Yes\n");
else printf("No\n");
}
return 0;
}
#10. 51nod 1012
##lcm 算了还是不一个一个做了,这种水题。。。还是二分一下适合我的题。
#include
#include
#include
#define LL long long
using namespace std;
LL gcd(LL a, LL b){
return b ? gcd(b, a%b) : a;
}
int main(){
LL a, b;
scanf("%lld %lld", &a, &b);
printf("%lld\n", a/gcd(a ,b)*b);
return 0;
}
#11. 51nod 1181
题意:如果一个质数,在质数列表中的编号也是质数,那么就称之为质数中的质数。例如:3 5分别是排第2和第3的质数,所以他们是质数中的质数。现在给出一个数N,求>=N的最小的质数中的质数是多少?
题解:N范围是1e6,考虑用线性筛筛出1e7以下的素数,再把下标是素数的另存一个数组,二分查找答案即可。
#include
#include
#include
#include
using namespace std;
const int maxn = (int)(1e7+100);
int p[maxn], v[maxn];
int pp[maxn];
int m, t;
void pre(){
memset(v, 0, sizeof(v));
for(int i = 2; i <= maxn; i++){
if(v[i] == 0){
v[i] = i;
p[++m] = i;
}
for(int j = 1; j <= m; j++){
if(v[i] < p[j] || p[j] > maxn/i) break;
v[i*p[j]] = p[j];
}
}
for(int i = 1; i <= m; i++){
if(v[i] == i){
pp[++t] = p[i];
//printf("%d ", i);
}
}
}
int main(){
pre();
int n;
scanf("%d", &n);
int x = lower_bound(pp+1, pp+t+1, n) - pp;
printf("%d\n", pp[x]);
return 0;
}
#12. 51nod 1080
题意:给出一个整数N,将N表示为2个整数i与j的平方之和(i <= j),如果有多种表示,按照i的递增序输出。
例如:N = 130,130 = 3^2 + 11^2 = 7^2 + 92(注:32 + 112同112 + 3^2算1种)
题解:i最大sqrt(n/2),暴力枚举即可。
#include
#include
#include
#include
using namespace std;
int v[40005];
int main(){
int n, t, flag = 1;
memset(v, 0, sizeof(v));
scanf("%d", &n);
t = (int)sqrt(n/2);
for(int i = 0; i <= t; i++){
int x = n - i*i;
int y = (int)sqrt(x);
if(y*y == x && !v[y]){
printf("%d %d\n", i, y);
v[i] = 1;
flag = 0;
}
}
if(flag){
printf("No Solution\n");
}
return 0;
}
#13. 51nod 1010
题意: K的因子中只包含2 3 5。满足条件的前10个数是:2,3,4,5,6,8,9,10,12,15。
所有这样的K组成了一个序列S,现在给出一个数n,求S中 >= 给定数的最小的数。
例如:n = 13,S中 >= 13的最小的数是15,所以输出15。
题解: 预处理出1e18内的这样的数,二分查找即可。
#include
#include
#include
#include
#include
#define LL long long
using namespace std;
const LL maxn = (LL)1e18+100LL;
int T;
LL n;
LL num[1000005], tot;
void pre(){
tot = 0;
for(LL i = 1; i <= maxn; i *= 2LL){
for(LL j = 1; i*j <= maxn; j *= 3LL){
for(LL k = 1; i*j*k <= maxn; k *= 5LL){
if(i*j*k != 1)
num[++tot] = i*j*k;
}
}
}
sort(num+1, num+tot+1);
}
int main(){
pre();
scanf("%d", &T);
while(T--){
scanf("%lld", &n);
int x = lower_bound(num+1, num+1+tot, n) - num;
printf("%lld\n", num[x]);
}
return 0;
}
#14. 51nod 1126
**题意:**有一个序列是这样定义的:f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7.
给出A,B和N,求f(n)的值。
题解::矩阵快速幂,转移矩阵为 [ 0 B 1 A ] \begin{bmatrix} 0&B\\1&A\\ \end{bmatrix} [01BA],不过要注意负数要加mod再mod。
#include
#include
#include
#include
#include
using namespace std;
const int mod = 7;
int A, B, n;
void mul(int f[2], int a[2][2]){
int c[2];
memset(c, 0, sizeof(c));
for(int i = 0; i < 2; i++){
for(int j = 0; j < 2; j++){
c[i] = ( c[i] + (long long)f[j] * a[j][i] ) % mod;
}
}
memcpy(f, c, sizeof(c));
}
void mulself(int a[2][2]){
int c[2][2];
memset(c, 0, sizeof(c));
for(int i = 0; i < 2; i++){
for(int j = 0; j < 2; j++){
for(int k = 0; k < 2; k++){
c[i][j] = ( c[i][j] + (long long)a[i][k] * a[k][j] ) % mod;
}
}
}
memcpy(a, c, sizeof(c));
}
int main(){
scanf("%d%d%d",&A,&B,&n);
int f[2] = {1, 1};
int a[2][2];
a[0][0]= 0, a[1][0] = 1;
a[0][1] = B, a[1][1] = A;
n -= 1;
for(; n; n >>= 1){
if(n & 1) mul(f, a);
mulself(a);
}
printf("%d\n", (f[0]+mod) % mod);
return 0;
}
#15. 51nod 1014
题意: X*X mod P = A,其中P为质数。给出P和A,求<=P的所有X。
**题解:**枚举x即可。
#include
#include
#include
#include
#include
#define LL long long
int main(){
int p, a, flag = 0;
scanf("%d%d", &p, &a);
for(int i = 0; i <= p; i++){
LL x = (LL)i*i;
if(x % p == a){
printf("%d ", i);
flag = 1;
}
}
if(!flag)
printf("No Solution\n");
return 0;
}
#16. 51nod 1352
**题意:**给出N个固定集合{1,N},{2,N-1},{3,N-2},…,{N-1,2},{N,1}.求出有多少个集合满足:第一个元素是A的倍数且第二个元素是B的倍数。提示:对于第二组测试数据,集合分别是:{1,10},{2,9},{3,8},{4,7},{5,6},{6,5},{7,4},{8,3},{9,2},{10,1}.满足条件的是第2个和第8个。
题解:
1.设满足条件的是 ( t 1 , t 2 ) (t1, t2) (t1,t2), 即 ( A x , B y ) (Ax, By) (Ax,By),所以有 A x + B y = n + 1 Ax+By=n+1 Ax+By=n+1,转化为求这个方程的满足 1 < = A x < = n , 1 < = B y < = n 1<=Ax<=n, 1<=By<=n 1<=Ax<=n,1<=By<=n的解的个数。
2.先用扩展欧几里得求出 A x + B y = g c d ( A , B ) Ax+By=gcd(A, B) Ax+By=gcd(A,B)的一个解 x 0 x_0 x0,那么原方程的一个解就是 x 0 ∗ n + 1 d x_0*\frac {n+1}d x0∗dn+1.
3.公式变形: A x + B y = n + 1 Ax+By=n+1 Ax+By=n+1 => A ( x + t ∗ B g c d ( A , B ) ) + B ( y − t ∗ A g c d ( A , B ) ) = n + 1 A(x+t*\frac {B}{gcd(A,B)}) + B(y - t*\frac{A}{gcd(A,B)}) = n+1 A(x+t∗gcd(A,B)B)+B(y−t∗gcd(A,B)A)=n+1
4.所以当 x x x 增加 B g c d ( A , B ) \frac{B}{gcd(A,B)} gcd(A,B)B时, y y y相应的减少 A g c d ( A , B ) \frac{A}{gcd(A,B)} gcd(A,B)A.然后计数在 1 ∼ n 1\sim n 1∼n的即可。
#include
#include
#include
#define LL long long
LL exgcd(LL a, LL b, LL &x, LL &y){
if(b == 0){
x = 1, y = 0;
return a;
}
LL d = exgcd(b, a%b, x, y);
LL z = x; x = y; y = z - y * (a/b);
return d;
}
int main(){
int t;
LL n, a, b;
scanf("%d", &t);
while(t--){
LL d, x0, y0;
scanf("%lld%lld%lld", &n, &a, &b);
d = exgcd(a, b, x0, y0);
if((n+1) % d){
printf("0\n");
continue;
}
LL dt = b/d;
//printf("x00:%d\n", x0);
x0 *= (n+1)/d;
x0 %= dt;
while(x0 <= 0) x0 += b/d;
//printf("x0:%d\n", x0);
LL tmp = n - x0*a;
if(tmp < 0){
printf("0\n");
continue;
}
LL lc = a*b/d;
printf("%lld\n", 1+tmp/lc);
}
}
#17. 51nod 1247
**题意:**在一个无限大的二维网格上,你站在(a,b)点上,下一步你可以移动到(a + b, b), (a, a + b), (a - b, b), 或者 (a, a - b)这4个点。给出起点坐标(a,b),以及终点坐标(x,y),问你能否从起点移动到终点。如果可以,输出"Yes",否则输出"No"。例如:(1,1) 到 (2,3),(1,1) -> (2,1) -> (2,3)。
**题解:**只需判断是否能到达即可,所以考虑这两对数之间肯定有相同的地方,很自然的会想到最大公约数。
那么为什么是最大公约数呢,首先变化是可逆的,题目给的操作要么两数之和,要么两数之差,这两个是可逆的。其次,就是从更相减损术来的,题目的操作其实就是更相减损术的流程。
#include
#include
#define LL long long
using namespace std;
LL gcd(LL a, LL b){
return b ? gcd(b, a%b) : a;
}
int main(){
int T;
scanf("%d", &T);
while(T--){
LL a, b, c, d;
scanf("%lld%lld%lld%lld", &a, &b, &c, &d);
if(gcd(a, b) == gcd(c, d))
printf("Yes\n");
else printf("No\n");
}
return 0;
}
#18. 51nod 1035
**题意:**正整数k的倒数1/k,写为10进制的小数如果为无限循环小数,则存在一个循环节,求<=n的数中,倒数循环节长度最长的那个数,假如存在多个最优的答案,输出所有答案中最大的那个数。1/6= 0.1(6) 循环节长度为11/7= 0.(142857) 循环节长度为61/9= 0.(1) 循环节长度为1
**题解:**建议阅读:http://w3.math.sinica.edu.tw/math_media/d253/25311.pdf
#include
#include
#include
#include
#define LL long long
using namespace std;
int phi[1005];
int gcd(int a, int b){
return b ? gcd(b, a%b) : a;
}
LL Pow(int a, int b, int p){
LL ans = 1;
while(b){
if(b & 1)
ans = ans*a%p;
b >>= 1;
a = a*a%p;
}
return ans;
}
void Phi(int n){
for(int i = 2; i <= n; i++) phi[i] = i;
for(int i = 2; i <= n; i++){
if(phi[i] == i){
for(int j = i; j <= n; j += i){
phi[j] = phi[j]/i*(i-1);
}
}
}
}
int main(){
int n, res = 0, len = 0;
scanf("%d", &n);
Phi(n);
for(int i = 2; i <= n; i++){
if(gcd(10, i) != 1)
continue;
int t = phi[i];
for(int j = 1; j <= t; j++){
if(t % j == 0 && Pow(10, j, i) == 1){
if(j > len){
len = j;
res = i;
}
break;
}
}
}
printf("%d\n", res);
return 0;
}
#19. 51nod 1116
题意: 有一个字符串S,记录了一个大数,但不知这个大数是多少进制的,只知道这个数在K进制下是K - 1的倍数。现在由你来求出这个最小的进制K。例如:给出的数是A1A,有A则最少也是11进制,然后发现A1A在22进制下等于4872,4872 mod 21 = 0,并且22是最小的,因此输出k = 22(大数的表示中A对应10,Z对应35)。
**题解:**设这个数的K进制表示为 a n ∗ K n − 1 + a n − 1 ∗ K n − 2 + ⋯ + a 2 ∗ K + a 1 a_n*K^{n-1}+a_{n-1}*K^{n-2}+\dots+a_2*K+a_1 an∗Kn−1+an−1∗Kn−2+⋯+a2∗K+a1
由公式 x n − 1 = ( x − 1 ) ( 1 + x + x 2 + ⋯ + x n − 1 ) x^n-1=(x-1)(1+x+x^2+\dots+x^{n-1}) xn−1=(x−1)(1+x+x2+⋯+xn−1)。对上式中的每一项
a i ∗ K i − 1 = a i ∗ ( ( K − 1 ) ( 1 + ⋯ + K i − 1 ) + 1 ) = a i ∗ ( K − 1 ) ( 1 + ⋯ + K i − 1 ) + a i a_i*K^{i-1}=a_i*\biggr ((K-1)(1+\dots+K^{i-1})+1 \biggr)=a_i*(K-1)(1+\dots+K^{i-1})+a_i ai∗Ki−1=ai∗((K−1)(1+⋯+Ki−1)+1)=ai∗(K−1)(1+⋯+Ki−1)+ai
通过上式不难发现,第一项是能被 K − 1 K-1 K−1整除的,所以只要所有系数之和能被 K − 1 K-1 K−1整除,这个数也就能被 K − 1 K-1 K−1整除。
#include
#include
#include
#include
#include
#define LL long long
using namespace std;
char s[100005];
int t[1000005];
LL ans = 0;
int main(){
int ma = -1;
scanf("%s", s);
int len = strlen(s);
for(int i = 0; i < len; i++){
if(s[i] >= '0' && s[i] <= '9')
t[i] = s[i] - 48;
if(s[i] >= 'A' && s[i] <= 'Z')
t[i] = s[i] - 65 + 10;
ma = max(ma, t[i]+1);
ans += t[i];
}
for(int i = ma; i <= 36; i++){
if(ans % (i-1) == 0){
printf("%d\n", i);
return 0;
}
}
printf("No Solution\n");
return 0;
}
#20. 51nod 1179
题意:给出N个正整数,找出N个数两两之间最大公约数的最大值。例如:N = 4,4个数为:9 15 25 16,两两之间最大公约数的最大值是15同25的最大公约数5。
题解:暴力枚举每个数的因数,用一个桶记录因数$\ i\ $的出现次数。再从max(a[i])往下扫,第一个出现次数大于等于2的就是答案。
#include
#include
#include
using namespace std;
int max(int a, int b){
return a > b ? a : b;
}
int n;
int a[50005], cnt[1000005];
int Max;
int main(){
Max = -1;
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
Max = max(a[i], Max);
}
for(int i = 1; i <= n; i++){
for(int j = 1; j*j <= a[i]; j++){
if(a[i] % j == 0){
cnt[j]++;
cnt[a[i]/j]++;
}
}
}
for(int i = Max; i >= 1; i--){
if(cnt[i] >= 2){
printf("%d\n", i);
break;
}
}
return 0;
}
#21. 51nod 1434
题意:现在给定一个整数N(1<=N<=1000000),需要找到一个整数M,满足M>N,同时LCM(1,2,3,4,…,N-1,N) 整除 LCM(N+1,N+2,…,M-1,M),即LCM(N+1,N+2,…,M-1,M)是LCM(1,2,3,4,…,N-1,N) 的倍数.求最小的M值。
题解:考虑 L C M ( 1 , 2 , . . . , N ) LCM(1,2,...,N) LCM(1,2,...,N)和 L C M ( N + 1 , . . . M ) LCM(N+1, ...M) LCM(N+1,...M)的质因数分解形式,易知大于 N N N的质数不用考虑,只用考虑 1 ∼ N 1\sim N 1∼N的质数。对于质数 P P P, 求出一个刚好满足 P t < = N P^t <= N Pt<=N的 t t t, 再找到一个系数 C C C使得 C ∗ P t > N C*P^t>N C∗Pt>N,所有满足条件中最大的就是M的值。
#include
#include
#include
#include
#include
#define LL long long
#define mem(a, b) memset(a, b, sizeof(a))
const int maxn = 1000005;
int cnt[maxn];
int p[maxn], v[maxn];
int tot = 0;
int max(int a, int b){
return a > b ? a : b;
}
void prime(int n){
mem(v, 0);
tot = 0;
for(int i = 2; i <= n; i++){
if(!v[i]){
v[i] = i;
p[++tot] = i;
}
for(int j = 1; j <= tot; j++){
if(v[i] < p[j] || p[j] > n/i) break;
v[i*p[j]] = p[j];
}
}
}
int T;
int main(){
prime(1000003);
scanf("%d", &T);
while(T--){
int n, ans = 2;
scanf("%d", &n);
for(int i = 2; i <= n; i++){
if(v[i] == i){
int k = 1;
while(k <= n/i){
k *= i;
}
for(int j = 2; ; j++){
if(k * j > n){
k *= j;
break;
}
}
ans = max(ans, k);
}
}
printf("%d\n", ans);
}
return 0;
}
#22. 51nod 1186
import random
def rand(l, r):
return int((r - l + 1) * random.random() + l)
def qpow(a, x, P):
ret = 1
while(x):
if(x & 1):
ret = ret * a % P
a = a * a % P
x >>= 1
return ret
def witness(a, n):
t = 0
u = n - 1;
while(not(u & 1)):
t += 1
u >>= 1
last = qpow(a, u, n)
for i in range(0, t):
cur = last * last % n
if(cur == 1 and last != 1 and last != n - 1):
return 1
last = cur
return (last != 1)
def miller_rabin(n, s):
if(n == 2):
return 1
for i in range(0, s):
a = rand(2, n - 1)
if witness(a, n):
return 0
return 1
n = int(input())
if(miller_rabin(n, 20)):
print("Yes")
else:
print("No")
#23. 51nod 1060
题意:
把一个数的约数个数定义为该数的复杂程度,给出一个n,求1-n中复杂程度最高的那个数。
例如:12的约数为:1 2 3 4 6 12,共6个数,所以12的复杂程度是6。如果有多个数复杂度相等,输出最小的。
题解:
1.题目所求就是反素数(自行百度)
2.由于N的范围(1e18),1-N的数不同质因子个数不超过16,因为这16个质因子乘起来就大于1e18了。而且所有质因子的指数和不会很大。
3.x是反素数的必要条件是它的质因子由若干个连续的最小的质数构成,且质数单调递减。
因为若不是这样,则可以通过交换质因子的方法得到一个比x小,但约数个数相等的数。
其他:与BZOJ 1035类似
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
const int prime[16] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
LL n;
LL ans = 1, ans_num = 1;
void dfs(int now, LL mul, LL num, LL last){
if(now >= 16)
return;
else{
if(num > ans_num){
ans_num = num;
ans = mul;
}
else if(num == ans_num){
ans = min(mul, ans);
}
LL i;
for(i = 1; i <= last; i++){
if(mul <= n/prime[now]){
mul *= prime[now];
dfs(now+1, mul, num*(i+1), i);
}
else
break;
}
}
}
int main(){
int T;
scanf("%d", &T);
while(T--){
ans = ans_num = 1;
scanf("%lld", &n);
dfs(0, 1, 1, 15);
printf("%lld %lld\n", ans, ans_num);
}
return 0;
}
#24. 51nod 1341
##题意:
给出两个数列 a n , b n a_n,b_n an,bn求 ( ∑ i = 0 n a i b n − i ) % ( 1 e 9 + 7 ) (\sum_{i=0}^n{a_ib_{n-i}})\%(1e9+7) (∑i=0naibn−i)%(1e9+7)
##题解:
令 c n = a 0 b n + a 1 b n − 1 + ⋯ + a n b 0 c_n=a_0b_n+a_1b_{n-1}+\dots+a_nb_0 cn=a0bn+a1bn−1+⋯+anb0
则 c n + 1 = a 0 b n + 1 + a 1 b n + ⋯ + a n b 1 + a n + 1 b 0 c_{n+1}=a_0b_{n+1}+a_1b_n+\dots+a_nb_1+a_{n+1}b_0 cn+1=a0bn+1+a1bn+⋯+anb1+an+1b0
观察可得: c n + 1 = q c n + a n + 1 b 0 c_{n+1}=qc_n+a_{n+1}b_0 cn+1=qcn+an+1b0
于是构建矩阵 A = ( q 0 0 b 0 ∗ q p 0 b 0 1 1 ) A=\begin{pmatrix} q&0&0\\b_0*q&p&0\\b_0&1&1 \end{pmatrix} A=⎝⎛qb0∗qb00p1001⎠⎞使得 [ c n + 1 a n + 1 r ] = [ c n a n r ] ( q 0 0 b 0 ∗ q p 0 b 0 1 1 ) \begin{bmatrix} c_{n+1} \quad a_{n+1}\quad r\end{bmatrix}= \begin{bmatrix} c_n\quad a_n \quad r\end{bmatrix} \begin{pmatrix} q&0&0\\b_0*q&p&0\\b_0&1&1 \end{pmatrix} [cn+1an+1r]=[cnanr]⎝⎛qb0∗qb00p1001⎠⎞
于是 [ c n a n r ] = [ c 0 a 0 r ] A n \begin{bmatrix} c_n\quad a_n \quad r\end{bmatrix}= \begin{bmatrix} c_0\quad a_0 \quad r\end{bmatrix}A^n [cnanr]=[c0a0r]An
可得 c n = r ∗ A n c_n=r*A^n cn=r∗An
矩阵快速幂可解决。
##代码:
#include
#include
#include
#include
#include
#define LL long long
const int MOD = 1000000007;
struct Mat{
LL ma[3][3];
};
Mat mul(Mat a, Mat b){
Mat c;
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
c.ma[i][j] = 0;
for(int k = 0; k < 3; k++){
c.ma[i][j] = c.ma[i][j] + a.ma[i][k]*b.ma[k][j]%MOD;
c.ma[i][j] = (c.ma[i][j]%MOD+MOD)%MOD;
}
}
}
return c;
}
Mat pow(Mat a, LL b){
Mat ans;
memset(ans.ma, 0, sizeof(ans.ma));
for(int i = 0; i < 3; i++){
ans.ma[i][i] = 1;
}
while(b){
if(b & 1)
ans = mul(ans, a);
b >>= 1;
a = mul(a, a);
}
return ans;
}
int main(){
LL p,q,r,n;
scanf("%lld%lld%lld%lld", &p, &q, &r, &n);
Mat x;
x.ma[0][0] = q, x.ma[0][1] = 0, x.ma[0][2] = 0;
x.ma[1][0] = 3*p%MOD, x.ma[1][1] = p, x.ma[1][2] = 0;
x.ma[2][0] = 3, x.ma[2][1] = 1, x.ma[2][2] = 1;
x = pow(x, n);
LL ans = (x.ma[2][0]*r%MOD+MOD)%MOD;
printf("%lld\n", ans);
return 0;
}
#25. 51nod 1189(待写)
#25. 51nod 1262(待写)