D. The Number of Pairs

传送门

(我发现这样的题目都是分解因子)

我们设a = Ag, b = Bg, lcm = (Ag * Bg) / g = AB * g, 此时方程可化为g(c * AB - d) = x。由此我们可以知道,g一定为x的一个因子, 那么(cAB - d)就是另外一个因子。当我们求得一个因子i,令g = i, 则 AB * c = x/i + d, 当x/i + d能被c整除时,我们可以得到AB的值。因为gcd(A,B) == 1,所以当我们找出AB的素因子后,该因子一定只能是A,B其中一个的因子,所有我们可以找出AB的所有素因子将他们分配给A和B,一共就有2^cnt种情况( C(n,0) + C(n, 1) …)
a = A
g, b = B*g, 故a, b的组合数就等于A, B的组合数.

算法实现

#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<utility>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cctype>
using namespace std;
 
typedef long long LL;           //数据太大了记得用LL,还有把INF也得换
typedef pair<int, int> P;
 
const int maxn = 2e7+10;        //cf数组最多差不多是这么多,1e8就会段错误
const int V_MAX = 800 + 10;
const int mod = 10007;
const int INF = 0x3f3f3f3f;     //如果数据范围为long long,记得把INF的值换了
const double eps = 1e-6;        //eps开太小二分容易死循环,所以直接来个100次循环就好了


                                //多组输入时,maxn太大,用memset()会超时,血的教训;

int mind[maxn], val[maxn];

void solve() {
    int c, d, x;
    cin >> c >> d >> x;
    int res = 0;
    for(int i = 1; i*i <= x; i++) {
        if(x % i != 0) continue;
        int k1 = x/i + d;
        if(k1 % c == 0) res += 1 << val[k1 / c];
        if(i * i == x) continue;
        int k2 = i + d;
        if(k2 % c == 0) res += 1 << val[k2 / c];
    }
    cout << res << endl;
}

int main()
{
    ios::sync_with_stdio(false);           //关了流同步就别用c的输入
    //freopen("D:\\in.txt", "r", stdin);
    //先求出每个数的素因子个数.
    memset(mind, -1,sizeof mind);
    mind[1] = 1;
    for(int i = 2; i <= maxn; i++) {
        if(mind[i] == -1) {
            for(int j = i; j <= maxn; j += i) {
                mind[j] = i;
            }
        }
    }
    for(int i = 2; i <= maxn; i++) {
        int t = i / mind[i];
        val[i] = val[t] + (mind[i] != mind[t]);
    }
   int t; cin >> t;
    while(t--) {
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
用c++解决1160. Network Time limit: 1.0 second Memory limit: 64 MB Andrew is working as system administrator and is planning to establish a new network in his company. There will be N hubs in the company, they can be connected to each other using cables. Since each worker of the company must have access to the whole network, each hub must be accessible by cables from any other hub (with possibly some intermediate hubs). Since cables of different types are available and shorter ones are cheaper, it is necessary to make such a plan of hub connection, that the maximum length of a single cable is minimal. There is another problem - not each hub can be connected to any other one because of compatibility problems and building geometry limitations. Of course, Andrew will provide you all necessary information about possible hub connections. You are to help Andrew to find the way to connect hubs so that all above conditions are satisfied. Input The first line contains two integer: N - the number of hubs in the network (2 ≤ N ≤ 1000) and M — the number of possible hub connections (1 ≤ M ≤ 15000). All hubs are numbered from 1 to N. The following M lines contain information about possible connections - the numbers of two hubs, which can be connected and the cable length required to connect them. Length is a positive integer number that does not exceed 106. There will be no more than one way to connect two hubs. A hub cannot be connected to itself. There will always be at least one way to connect all hubs. Output Output first the maximum length of a single cable in your hub connection plan (the value you should minimize). Then output your plan: first output P - the number of cables used, then output P pairs of integer numbers - numbers of hubs connected by the corresponding cable. Separate numbers by spaces and/or line breaks.
最新发布
05-28
以下是使用 C++ 解决 1160. Network 问题的代码: ```cpp #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <cstring> using namespace std; const int MAXN = 1005; const int MAXM = 15005; const int INF = 0x3f3f3f3f; struct Edge { int to, w, next; } edges[MAXM * 2]; int head[MAXN], cnt = 0; void addEdge(int u, int v, int w) { edges[++cnt].to = v; edges[cnt].w = w; edges[cnt].next = head[u]; head[u] = cnt; } int n, m; int d[MAXN]; // 存储每个点到最小生成树的距离 bool vis[MAXN]; int parent[MAXN]; // 存储最小生成树中每个节点的父节点 int max_len = -1; void prim() { memset(d, INF, sizeof(d)); memset(vis, false, sizeof(vis)); memset(parent, -1, sizeof(parent)); d[1] = 0; priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q; q.push(make_pair(0, 1)); while (!q.empty()) { int u = q.top().second; q.pop(); if (vis[u]) continue; vis[u] = true; for (int i = head[u]; i; i = edges[i].next) { int v = edges[i].to; int w = edges[i].w; if (!vis[v] && d[v] > w) { d[v] = w; q.push(make_pair(d[v], v)); parent[v] = u; } } } } int main() { cin >> n >> m; for (int i = 1; i <= m; i++) { int u, v, w; cin >> u >> v >> w; addEdge(u, v, w); addEdge(v, u, w); } prim(); vector<pair<int, int>> ans; for (int i = 2; i <= n; i++) { ans.push_back(make_pair(i, parent[i])); max_len = max(max_len, d[i]); } cout << max_len << endl; cout << ans.size() << endl; for (int i = 0; i < ans.size(); i++) { cout << ans[i].first << " " << ans[i].second << endl; } return 0; } ``` 解释如下: 首先,我们定义一个边结构体 `Edge`,其中包括两个属性:`to` 表示边指向哪个节点,`w` 表示边的权值。然后,我们定义一个 `head` 数组,用于存储每个节点的第一条边。 接着,我们编写 `addEdge` 函数,用于加边。由于是无向图,所以需要加两次边。 在 `main` 函数中,我们首先读入节点数 `n` 和边数 `m`,然后读入每条边,并调用 `addEdge` 函数加边。 接下来,我们调用 `prim` 函数计算最小生成树。具体过程如下: 1. 初始化 `d` 数组为正无穷,`vis` 数组为 `false`,`parent` 数组为 `-1`,并将 `d[1]` 设为 0。 2. 将 `(0, 1)` 加入优先队列 `q`。 3. 当 `q` 不为空时,取出队首元素 `(dist, u)`,如果 `u` 已被访问过,则继续取队首元素。 4. 将 `u` 标记为已访问。 5. 遍历 `u` 的所有相邻节点 `v`,如果 `v` 未被访问过且 `d[v] > w(u, v)`,则更新 `d[v]` 为 `w(u, v)`,将 `(w(u, v), v)` 加入优先队列,并将 `parent[v]` 设为 `u`。 最后,我们遍历所有非根节点,并将它们与它们的父节点加入答案数组 `ans`,同时更新最大边长 `max_len`。最后输出答案即可。 注意,本题中所有边权均为正整数,因此我们可以将 `d` 数组初始化为正无穷,而不是负无穷。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值