繁体   English   中英

乘积模随机数

[英]Product modulo random numbers

素数p是固定的。 给出了 n 个数字的序列,每个数字从1p - 1 众所周知,序列中的数字是随机选择的,可能性相等且彼此独立。 从序列中选择一些数字,使它们的乘积以p为模,等于给定的数字x 如果没有选择数字,则认为乘积等于 1。

输入:

第一行包含三个由空格分隔的整数:序列的长度n 、素数p和所需的值x

(n=100, 2<=p<=10^9, 0<x<p)

接下来,写入n整数,以空格或换行符分隔:序列a1 , a2 ,。 . ., an

(0 <ai <p)

输出:

从乘积模p等于x的序列中打印数字。 数字显示的顺序并不重要。 如果有多个可能的答案,请打印其中任何一个

例子:

INPUT:

100 11 4
9 6 1 1 10 4 9 10 3 1 10 1 6 8 3 3 9 8
10 3 7 7 1 3 3 1 5 2 10 4 1 5 6 7 2 6
2 8 3 3 6 7 6 3 1 5 10 2 2 10 9 6 8 6
2 10 3 2 7 4 3 2 8 6 4 1 7 2 10 8 4 9
7 9 8 7 4 7 3 2 8 2 3 7 1 5 2 10 7 1 8
6 4 10 10 3 6 10 2 1

OUTPUT:
4 6 10 9

我的解决方案:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std; 

int main()
{
    int n,p,x,y,m,k,tmp; 

    vector<int> v;
    cin >> n >> p >> x;
    for (int i = 0; i<n; i++){
        cin >> tmp;
        v.push_back(tmp);
    } 

    sort(v.begin(), v.end());
    v.erase(v.begin(), upper_bound(v.begin(), v.end(), 1));

    k=-1;
    while(1){
        k++;
        m = 1;
        y = x+p*k;;
        vector<int> res; 
        for (int i = 0; i<n; i++){ 
            if (y == 1) break;
            if ( y%v[i] == 0){
                res.push_back(v[i]);
                m*=v[i];
                m%=p;
                y = y/v[i];
            }
        } 
        if (m==x) {
            for (int i = 0; i<res.size(); i++){
                cout << res[i] << " ";
            }
            break;
        }

    } 

    return 0;
}

在我的解决方案中,我使用了条件( y=x+k*p ,其中y是答案中数字的乘积, k是某种自然数)。 并且还迭代了值k

此解决方案有时会超出分配的时间。 请告诉我一个更正确的算法。

在此处输入图片说明

我会考虑对输入列表的散列多集进行回溯例程。 由于p是素数,因此我们可以随时考虑当前倍数m是否在我们的多重集中(multiplicative_inverse(m, p) * x) % p ( https://en.wikipedia.org/wiki/Multiplicative_inverse ) . 如果它存在,我们就完成了。 否则,尝试乘以我们当前在多重集中访问的相同数字,或乘以下一个(保持乘法模p的结果)。

请参阅下面的评论以获取 Python 示例代码的链接。 你给出的例子有一些简单的解决方案,所以有一些重要的,以及具有挑战性的例子来测试和改进会很有帮助。 还请说明输出中是否需要多个数字。

您可以使用动态编程方法。 它需要 O(p) 个内存单元和 O(p*n) 次循环迭代。 可能有多种优化(排除处理输入重复,或打印最长/最短选择链)。 以下是最简单和基本的 DP 程序,演示了这种方法。

#include <stdio.h>
#include <stdlib.h>

int data[] = {
9, 6, 1, 1, 10, 4, 9, 10, 3, 1, 10, 1, 6, 8, 3, 3, 9, 8,
10, 3, 7, 7, 1, 3, 3, 1, 5, 2, 10, 4, 1, 5, 6, 7, 2, 6,
2, 8, 3, 3, 6, 7, 6, 3, 1, 5, 10, 2, 2, 10, 9, 6, 8, 6,
2, 10, 3, 2, 7, 4, 3, 2, 8, 6, 4, 1, 7, 2, 10, 8, 4, 9,
7, 9, 8, 7, 4, 7, 3, 2, 8, 2, 3, 7, 1, 5, 2, 10, 7, 1, 8,
6, 4, 10, 10, 3, 6, 10, 2, 1
};

struct elm {
  int val;  // Value
  int prev; // from which elemet we come to this
  int n;    // add loop cound for prevent multiple use same val
};

void printsol(int n, int p, int x, const int *in) {
  struct elm *dp = (struct elm *)calloc(p, sizeof(struct elm));
  int i, j;
  for(i = 0; i < n; i++) // add initial elements into DP array
    dp[in[i]].val = in[i];
  for(i = 0; i < n; i++) { // add elements, one by one, to DP array
    if(dp[in[i]].val <= 1) // skip secondary "1" multipliers
      continue;
    for(j = 1; j < p; j++) 
      if(dp[j].val != 0 && dp[j].n < i) {
        int y = ((long)j * in[i]) % p;
        dp[y].val  = in[i]; // current value, for printout
        dp[y].prev = j; // reference to prev element
        dp[y].n    = n; // loop num, for prevent double reuse
        if(x == y && dp[x].n > 0) {
          // targed reached - print result, by iterate linklist
          int mul = 1;
          while(x != 0) {
            printf(" %d ", dp[x].val);
            mul *= dp[x].val; mul %= p;
            x = dp[x].prev;
          }
          printf("; mul=%d\n", mul);
          free(dp);
          return;
        }
      } // for+if
  } // for i
  free(dp);
}

int main(int argc, char **argv) {
  printsol(100, 11, 4, data);
  return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM