Codeforces Round #232 (Div. 2)

本文深入探讨了算法、编程语言、数据结构等核心领域的关键概念和技术应用,涵盖了从基础到高级的知识点,旨在帮助开发者提升技能,解决复杂问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A. On Segment's Own Points

题目:http://codeforces.com/contest/397/problem/A

大意:求N-1个区间在第一个区间上没有覆盖的长度,所有输入数据均在100以内。

思路:用一个标记数组F[ i ]表示区间[ i-1, i ]的覆盖次数,累计第一个区间上覆盖次数为1 的单位区间就是答案。

Code:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

int f[200], l[200], r[200];
int m = 0;
int main() {
    int n; cin>>n;
    for (int i=1; i<=n; i++){
        cin >> l[i] >> r[i];
        for (int j=l[i]+1; j<=r[i]; j++)
            f[j] ++;
    }
    int s = 0;
    for (int i=l[1]+1; i<=r[1]; i++){
        //cout << i <<' ' << f[i] <<endl;
        if (f[i] == 1) s ++;
    }
    cout <<s << endl;

    return  0;
}




B. On Corruption and Numbers

题目:http://codeforces.com/contest/397/problem/B

大意:1000个询问,整数N是否能由区间[ Li,Ri]中的整数若干次加得,数据范围在10^9以内。

思路:一个[Li, Ri]中的数可以表示范围[Li,Ri]

            俩个[Li, Ri]中的数可以表示范围[2×Li,2×Ri]

            ... ...

            那么K个[Li,Ri]中的数可以表示范围[K×Li,K×Ri]

            由此得到算法 : K = N div L  // 最少需要K个数相加

                                          判断 K × R >= N 是否成立即可

           Ps : K ×R需要用到long long

Code:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

int n, l, r;
long long k, x, t;
int main(){
    int T; cin >> T;
    while(T--){
        scanf("%d %d %d", &n, &l, &r);
        k = n / l;
        //cout << k << ' ' << k * r <<endl;
        if (k * r >= n) printf("Yes\n");
            else printf("No\n");
    }

    return 0;
}




C. On Number of Decompositions into Multipliers

题目:http://codeforces.com/contest/397/problem/C

大意:给定M,将M重新划分为N个数的乘积,问有多少种分法,N<=500,Ai<=10^9

思路:从质因数的角度考虑,将M看做P1^K1 * P2^K2 * P3^K3 *  ... ...  *Pm^Km = M,Pi为M的质因数

由于划分是乘法,显然每个Pi之间可看作独立的部分;

那么Ki个Pi划分成N个部分,相当于将Ki个相同的球放入N个不同的盒子,允许空盒,用隔板法可知方案数为C(N+Ki-1,N-1);

将每个Pi的答案累乘就得到最后的答案;

完整的算法为:

预处理组合公式C[A, B] = C[A-1,B] + C[A-1,B-1] ;

把每个Ai质因数分解,用Map存放并累计每个质因数的个数;

最后遍历Map,累乘得到最后的答案

注意考虑分解质因数时排除1的情况,预处理组合公式时可用记忆化搜索优化,数据类型用long long

Code:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
using namespace std;
#define LL long long
#define MOD 1000000007
#define maxn 20000
#define maxm 510

map<int, int> pri;
LL c[maxn][maxm];

void add(int x){
    for (int i=2; i*i<=x; i++){
        int t = 0;
        while (x % i == 0){
            t ++;
            x /= i;
        }
        pri[i] += t;
    }
    if (x > 1) pri[x] ++;
}

LL comb(int a, int b){
    if (c[a][b]) return c[a][b];
    if (a == b || b == 0) return 1;

    return c[a][b] = (comb(a-1,b)+ comb(a-1,b-1))%MOD;
}

int main(){
    int n; scanf("%d", &n);
    for (int i=1; i<=n; i++){
        int x; scanf("%d", &x);
        if (x > 1) add(x);
    }
    LL ans = 1;
    for (map<int, int> ::iterator i=pri.begin(); i!=pri.end(); i++){
        int m = (*i).second;
        //cout << (*i).first << ' ' << m << endl;
        //cout << n+m-1 << ' ' << n-1 << ' ' << comb(n+m-1,n-1) <<endl;
        ans = (ans * comb(n+m-1, n-1))%MOD;
    }
    cout << ans <<endl;

    return 0;
}


D. On Sum of Fractions

题目:http://codeforces.com/contest/397/problem/D

大意:定义v(i)是不超过i的最大质数,u(i)是严格大于i的最小质数,给定N,求

思路:用Pri[i]表示从质数,Pri[1] = 2,Pri[M] = u(N);

那么Ans = (Pri[2] - Pri[1]) \ (Pri[1] * Pri[2]) + (Pri[3] - Pri[2]) \ (Pri[2] * Pri[3]) + ... ...  + (N - Pri[M-1]) \ (Pri[M-1] * Pri[M]) ;

将上式列项,有(Pri[k] - Pri[k-1]) \ (Pri[k-1] * Pri[k]) = 1 \ Pri[k-1]  - 1 \ Pri[k] ;

那么1° 若N = u(N)-1,显然Ans = 1 \ Pri[1] - 1 \ Pri[M] = 1 \ 2 - 1 \ u(N);

        2° 若N ≠ u(N)-1,那么令 x = (u(N)- v(N)) - (N - v(N)+1)有Ans = 1 \ 2 - 1 \ u(N) - x \ u(N) * v(N);

最后算出分子分母除以gcd约分即可,数据范围需要用到long long

又10^18内的素数分布稠密,可以直接For循环求解u(N)v(N)

Code:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const long long maxn = 1e10;

long long n;
long long p, q;

bool prime(long long x){
    for (int i=2; i<=sqrt(x); i++)
        if (x % i == 0) return false;
    return true;
}

long long lower(long long x){
    while (! prime(x))
        x --;

    return x;
}

long long higher(long long x){
    x++;
    while (! prime(x))
        x ++;

    return x;
}

long long gcd(long long a, long long b){
    if (a == 0) return b;
    if (b == 0) return a;
    return gcd(b, a % b);
}

int main(){
    int T; cin >> T;
    while(T--){
        scanf("%d", &n);
        p = lower(n);
        q = higher(n);
        long long m = p*q;
        long long x = (q-p)-(n-p+1);
        x = m - 2*p - 2*x;  m *= 2;
        long long k = gcd(x, m);
        //cout << p << ' ' << q << ' '<< x << endl;
        cout << x/k << '/' << m/k << endl;
    }

    return 0;
}


小结:

1° Map的用法
Map<int, int> name 第一个键值可以直接访问下标,但不可修改。
遍历Map for (int map<int, int> :: iterator i=name.begin(); i!=name.end();i++)
Map的两个键值访问 (*i).first (*i).second

2°分解质因数
直接从2遍历每次除到底即可,记得考虑最后剩余的除数是否存在。

3。素数分布
10^18内的素数分布稠密,找相邻的素数用for循环暴力查找时间消耗很小。 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值