2021牛客寒假算法基础集训营1 A-串(数学推公式) J 一群小青蛙呱蹦呱蹦呱(LCM)

题目链接:A-串  J一群小青蛙呱蹦呱蹦呱

A-串

题目大意

  • 长度不超过n,且包含子序列“us”的、只由小写字母构成的字符串有多少个? 答案对1e9+7取模。
  • 子序列,us可以不相邻
  • 范围:2≤n≤1e6

思路

  • 数学推公式。如果要看dp推状态的 点这里~
  • 正难则反,求不含us子序列的,比如n等于3。
  1. 三个都选没有s,那么总共25*25*25
  2. 最后一个选了s,那么之前就不能选u,总共25*25*1
  3. 第二个选了s,那么倒数第一个不能选s,因为会和2重复,第一个不可以是u,总共25*1*25
  4. 第一个选了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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43911947/article/details/113530909