Problem 1. facsum
题解
我们发现后面那个sigma里都是积性函数, 积性函数相乘也是积性函数. 我们可以线性筛筛除后面那个就可以.
考虑后面那个和式设为积性函数g, p为质数的话, g(p) = 2 - p. g(p ^ 2) = 3 - 2p. g(p ^ 3) = 4 - 3p, 以此类推. 然后用线性筛来筛, 若i 与 pr[j]互质的话, g(i * p[j]) = g[i] * g[pr[j]], 这是积性函数的性质.
如果不互质的, 由于线性筛某个数一定是被最小的质因子筛掉的, 所以记录一下某个数最小质因子的指数且值为多少. 在i与pr[j]不互质的情况下, 将i的pr[j]质因子抽出来使之互质即可.
#include<stdio.h>
typedef long long dnt;
const int mod = 1e9 + 7;
const int maxn = 1e7 + 5;
int n, m, tot;
bool mark[maxn + 5];
int pr[maxn + 5], t[maxn + 6];
dnt g[maxn + 5], f[maxn + 5], h[maxn + 5];
inline dnt mpow(dnt a){
dnt ans = 1, b = m;
while(b){
if(b & 1) ans = ans * a % mod;
a = a * a % mod, b >>= 1;
}
return ans;
}
inline void Linear_sieve(){
g[1] = 1; h[1] = 1;
for(int i = 2; i < maxn; ++i){
if(!mark[i]) pr[++tot] = i, g[i] = 2 - i, t[i] = 1, h[i] = i;
for(int j = 1; j <= tot && i * pr[j] < maxn; ++j){
int k = pr[j] * i;
mark[k] = true;
if(!(i % pr[j])){
t[k] = t[i] + 1;
h[k] = h[i] * pr[j] % mod;
g[k] = (g[i / h[i]] * (t[k] + 1 - t[k] * pr[j])) % mod;
break;
}
h[k] = pr[j];
t[k] = 1;
g[k] = g[i] * g[pr[j]] % mod;
}
}
}
inline void init_f(){
for(int i = 1; i <= n; ++i)
f[i]= ((f[i - 1] + mpow(i) * g[i]) % mod + mod) % mod;
}
int main(){
freopen("facsum.in", "r", stdin);
freopen("facsum.out", "w", stdout);
scanf("%d%d", &n, &m);
Linear_sieve();
init_f();
printf("%I64d\n", f[n]);
return 0;
}
Problem 2. group
Input file: group.in
Output file: group.out
Time limit: 1 second
Memory limit: 256 MB
Mr.Hu 最近在研究等比数列,即形如:
a; a^1; a^2; a^3; a^n;
现在,Mr.Hu 想知道,对于给定的非负整数a,上面这个无穷数列在摸mod 意义下有多少项是本质不同
的。(保证gcd(a; mod) = 1)。
Input
第1 行一个整数:T,表示数据组数。
接下来T 行,每行两个整数:a mod。
Output
对于每组数据,输出一行,包含一个整数,表示模意义下本质不同的数有多少个。
Sample
group.in group.out
21
3
2 5
14
对于第一组数据,数列是:1; 1; 1; 1;
对于第二组数据,数列(取模以后)是:2; 4; 3; 1; 2; 4; 3; 1; ,总共有4 个本质不同的数。
Note
• 对于30% 的数据,0 a 103,1 mod 103;
• 对于100% 的数据,0 a 2 109,1 mod 2 109,且保证gcd(a; mod) = 1,1 T 100。
题解
求出最小循环节. 求出最小x使a ^ x 同余 1即可. BSGS即可.
#include<stdio.h>
#include<cmath>
#include<cstring>
#define clear(a) memset(a, 0, sizeof(a))
const int S = 100007;
typedef long long dnt;
int p, T, num;
int h[S + 5];
struct edge{
dnt v;
int nxt, c;
}e[S * 2];
inline void insert(dnt x, int y){
// printf("%I64d %d\n", x, y);
dnt u = x % S;
for(int i = h[u]; i; i = e[i].nxt)
if(e[i].v == x){
e[i].c = y; return;
}
e[++num].v = x;
e[num].c = y;
e[num].nxt = h[u];
h[u] = num;
}
inline int query(dnt x){
// printf("%I64dxxxxxxxx\n", x);
dnt u = x % S;
for(int i = h[u]; i; i = e[i].nxt)
if(e[i].v == x) return e[i].c;
return -1;
}
inline dnt BSGS(dnt a, dnt b){
dnt m = ceil(sqrt(p)), mul = 1, val = b % p;
clear(h), num = 0;
insert(val, 0);
// printf("%I64dm\n", m);
for(int j = 1; j <= m; ++j){
mul = mul * a % p;
val = mul * b % p;
if(j != m) insert(val, j);
}
dnt am = mul;
// printf("%I64dam\n", am);
mul = 1;
for(int i = 1; i <= m; ++i){
mul = mul * am % p;
int j = query(mul);
if(~j) return i * m - j;
}
return -1;
}
int main(){
freopen("group.in", "r", stdin);
freopen("group.out", "w", stdout);
dnt a;
scanf("%d", &T);
while(T--){
scanf("%I64d%d", &a, &p);
printf("%I64d\n", BSGS(a, 1));
}
return 0;
}
Problem 3. ccount
题解
发现lucas实际就是将n和m模数进制下拆分. 那么就在5进制下数位dp, 看某一位C(n, i)是不是0即可. 注意n和i都是5进制下的.
用r的答案减去l-1的答案.
#include<stdio.h>
#include<cstring>
#define deeper(a) memset(a, -1, sizeof(a))
const int P = 5;
const int maxn = 1e2;
typedef long long dnt;
int T, utot, dtot;
int c[P][P], up[maxn], down[maxn];
dnt dp[maxn][6];
inline void init(){
for(int i = 0; i < P; ++i)
for(int j = 0; j <= i; ++j){
if(j == 0 || j == i) c[i][j] = 1;
else c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % P;
}
}
inline void calc(dnt x, int *arr, int &tot){
tot = 0;
if(!x)
arr[++tot] = 0;
while(x){
arr[++tot] = x % P;
x /= P;
}
}
dnt dfs(int pos, int r, int lim){
if(~dp[pos][r] && !lim) return dp[pos][r];
if(!pos) return !r;
dnt ed = 0;
int ban = (lim) ? down[pos] : P - 1;
for(int i = 0; i <= ban; ++i)
ed += dfs(pos - 1, r * c[up[pos]][i] % P, lim && i == ban);
if(!lim) dp[pos][r] = ed;
return ed;
}
inline dnt solve(dnt x){
calc(x, down, dtot);
return dfs(dtot, 1, true);
}
int main(){
freopen("ccount.in", "r", stdin);
freopen("ccount.out", "w", stdout);
init();
scanf("%d", &T);
while(T--){
dnt l, r, n;
scanf("%I64d%I64d%I64d", &l, &r, &n);
deeper(dp);
calc(n, up, utot);
dnt ans = solve(r);
if(l) ans -= solve(l - 1);
printf("%I64d\n", ans);
}
}