题目链接:A-串 J一群小青蛙呱蹦呱蹦呱
A-串
题目大意
- 长度不超过n,且包含子序列“us”的、只由小写字母构成的字符串有多少个? 答案对1e9+7取模。
- 子序列,us可以不相邻
- 范围:2≤n≤1e6
思路
- 数学推公式。如果要看dp推状态的 点这里~
- 正难则反,求不含us子序列的,比如n等于3。
- 三个都选没有s,那么总共25*25*25
- 最后一个选了s,那么之前就不能选u,总共25*25*1
- 第二个选了s,那么倒数第一个不能选s,因为会和2重复,第一个不可以是u,总共25*1*25
- 第一个选了s,那么第二个和最后一个都不能选s,因为会和之前的重复,总共1*25*25
- 随机选有26^3,去掉不含us子序列的25^2 * 3 + 25^3,那么剩下的就是包含us子序列的了
- 所以对于长度为n的串来说,us子序列的个数就是26^n - 25^(n - 1) * n + 25 ^ n,取模出现减法需要加mod再取模
ac代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod = 1e9 + 7;
const int maxn = 1e6 + 5;
ll _pow(ll a, ll b){
ll ans = 1;
while(b){
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
int main(){
int n; cin >> n;
ll ans = 0;
for(int i = 2; i <= n; i ++){
ans = (ans + _pow(26, i) - (i * _pow(25, i - 1) % mod + _pow(25, i)) % mod + mod) % mod;
}
cout << ans << endl;
return 0;
}
J一群小青蛙呱蹦呱蹦呱
题目大意
- 有n个格子,每个格子里有一个数,1,2,3,4...n
- 然后牛牛放出无穷只青蛙。第i只青蛙的路线是首项为1,公比为p(i)的等比数列,其中p(i)代表第i个素数。
- 当青蛙跳到一个格子上,如果这个格子上面有一个数,青蛙就会把这个数吃掉
- 问最终剩下的没有被吃掉的所有数的最小公倍数多大,对1e9+7取模
- 范围 1≤n≤1.6e8, 时限 2s
思路
- 一个数n,首先1肯定会被吃,然后要是分解质因子之后只有一个质因子,那么他肯定也会被吃掉, 所以存活的条件是他能分解出不只一个质因子
- 然后就是lcm的定理,比如三个数x, y, z的lcm,分别进行分解质因子之后 x = p1^a1 * p2^b1 * p3^c1, y = p1^a2 * p2^b2 * p3^c3, z = p1^a3 * p2^b3 * p3^c3,那么lcm=p1^(max(a1, a2, a3)) * p2^(max(b1, b2, b3)) * p3^(max(c1, c2, c3)),所以要找质因子的同时,还要找分解最多的数量
- 那么首先就要筛素数啦,这里使用了欧拉筛。
- 然后怎么才能分解跟多数量呢,如果此时质因子是2,那么为了多一个质因子,那么就找小一点的3,然后算最多的2与3相乘,其乘法结果不超过n;如果是其他质因子ci,那么可以找个2,计算最多的ci与2相乘,其乘法结果不超过n。最后将合理的质因子相乘就是其lcm。
ac代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 8e7 + 5; //给的上限的一半
const int mod = 1e9 + 7;
int v[N], prime[N], cnt = 0;
void get_prime(){ //欧拉筛
for(int i=2;i<=N;i++){
if(!v[i]){
v[i]=i;prime[++cnt]=i;
}
for(int j=1;j<=cnt&&i*prime[j]<=N;j++){
if(prime[j]>v[i])break;
v[i*prime[j]]=prime[j];
}
}
}
int main(){
get_prime();
int n; scanf("%d", &n);
if(n < 6){ //小于6的都会被吃
puts("empty");
return 0;
}
ll cc = 0, dd = 2; //质因子是2的另算,cc是能取2的最多数量
while(dd * 3 <= n) dd *= 2, cc ++;
ll ans = 1;
while(cc --) ans = (ans * 2) % mod; //cc个2相乘,就是pi^ai,最后lcm就是这些算式的乘积
for(int i = 2; i <= cnt && prime[i] * 2 <= n; i ++){
cc = 0, dd = prime[i];
while(dd * 2 <= n) dd *= prime[i], cc ++; //同理,其他质因子要与2配对,找最大的数量
while(cc --) ans = ans * prime[i] % mod;
}
printf("%lld\n", ans);
return 0;
}