UVA 1635 Irrelevant Elements [唯一分解定理]

本文探讨了一种新颖的随机数生成方法,该方法通过一系列步骤最终得到一个介于0到m-1之间的随机数。文章重点研究了在特定参数n和m下哪些初始随机数对最终结果没有影响,并提供了相应的算法实现。

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

Irrelevant Elements
Time Limit: 3000MS
Memory Limit: Unknown
64bit IO Format: %lld & %llu

Young cryptoanalyst Georgie is investigating different schemes of generating random integer numbers
ranging from 0 to m − 1. He thinks that standard random number generators are not good enough, so
he has invented his own scheme that is intended to bring more randomness into the generated numbers.
First, Georgie chooses n and generates n random integer numbers ranging from 0 to m − 1. Let
the numbers generated be a1, a2, … , an. After that Georgie calculates the sums of all pairs of adjacent
numbers, and replaces the initial array with the array of sums, thus getting n−1 numbers: a1 +a2, a2 +
a3, … , an−1 + an. Then he applies the same procedure to the new array, getting n − 2 numbers. The
procedure is repeated until only one number is left. This number is then taken modulo m. That gives
the result of the generating procedure.
Georgie has proudly presented this scheme to his computer science teacher, but was pointed out that
the scheme has many drawbacks. One important drawback is the fact that the result of the procedure
sometimes does not even depend on some of the initially generated numbers. For example, if n = 3
and m = 2, then the result does not depend on a2.
Now Georgie wants to investigate this phenomenon. He calls the i-th element of the initial array
irrelevant if the result of the generating procedure does not depend on ai
. He considers various n and
m and wonders which elements are irrelevant for these parameters. Help him to find it out.

Input
Input file contains several datasets. Each datasets has n and m (1 ≤ n ≤ 100 000, 2 ≤ m ≤ 109
) in a
single line.

Output
On the first line of the output for each dataset print the number of irrelevant elements of the initial
array for given n and m. On the second line print all such i that i-th element is irrelevant. Numbers
on the second line must be printed in the ascending order and must be separated by spaces.

Sample Input
3 2

Sample Output
1
2


通过画图观察,问题变成组合数 C(n-1,i) i∈[0,n-1] 中m的倍数是那些
由于m不一定是质数,所以不可以使用组合数线性递推公式,因为m的逆不一定存在,但是可以用另一个求逆元的公式

如果不使用合数逆元公式, 那么可以把 m 分解, 如果组合数中相同质数的指数更大,那么可以整除
由于从0开始到n-1, 那么时间复杂度 O(n)
又m的质因子不超过20个
那么可以在3000ms内解决此题
但是要注意当m剩一个大于sqrt(1e9) 的质数时, rev_p 数组存不下, 此时需要特判!
另一个RE的地方: 后面组合数公式递推时,如果这个质数不在m内,那么需要舍弃,否则RE
另外注意输出0的时候要有两个换行!!(注意读题)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
const int INF=0x3f3f3f3f;
const int maxn = 100005;
const int maxp = 20;
int prime[maxp]; // specific primes of m
int prime_m[maxp]; // cnt of m
int rev_p[maxn]; // reflection of prime in m
int prime_cnt;
inline bool get_m(int m)
{
    memset(prime_m,0,sizeof(prime_m));
    memset(rev_p,0,sizeof(rev_p));
    prime_cnt=0;
    int tmp = (int) sqrt(m+0.5);
    for(int i=2;i<=tmp;i++) if(m%i==0)
    {
        prime[++prime_cnt] = i; rev_p[i] = prime_cnt;
        while(m%i==0) prime_m[prime_cnt]++ , m/=i;
    }
    if(m>maxn-5) return false;
    if(m>1) prime[++prime_cnt]=m , prime_m[prime_cnt]++ ,rev_p[m] = prime_cnt;
    return true;
}
int current[maxp];
inline bool check()
{
    for(int i=1;i<=prime_cnt;i++)
        if(current[i]<prime_m[i]) return false;
    return true;
}
int ans[maxn];
int cnt;
void work(int n)
{
    cnt = 0;
    if(check()) ans[++cnt] = 1;
    for(int i=1;i<=n;i++)
    {
        int a = n - i + 1 , lima = (int) sqrt(a+0.5);
        int b = i , limb = (int) sqrt(b+0.5);
        for(int j=2;j<=lima;j++) if(a%j==0)
            while(a%j==0)
            {
                a/=j;
                if(rev_p[j]) current[rev_p[j]]++; // only the reflevtion exists, update!!!!!!
            }
        if(a>1 && rev_p[a]) current[rev_p[a]]++;
        for(int j=2;j<=limb;j++) if(b%j==0)
            while(b%j==0)
            {
                b/=j;
                if(rev_p[j]) current[rev_p[j]]--; // only the reflevtion exists, update!!!!!!
            }
        if(b>1 && rev_p[b]) current[rev_p[b]]--;
        if(check()) ans[++cnt] = i+1;
    }
}
inline void print()
{
    printf("%d\n",cnt);
    if(!cnt) return;
    for(int i=1;i^cnt;i++) printf("%d ",ans[i]);
    printf("%d",ans[cnt]);
}
int main()
{
    freopen("elements.in","r",stdin);
    freopen("elements.out","w",stdout);
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        if(!get_m(m))
        {
            printf("0\n\n");
            continue;
        }
        work(n-1);
        print();
        printf("\n");
    }
    return 0;
}
### 如何在 Excel 中获取唯一值 #### 使用公式法 通过使用内置的 Excel 函数可以实现提取唯一值的功能。例如,`UNIQUE` 函数可以直接用于现代版 Excel (Office 365 或更高版本),它能够返回数据范围内的唯一值列表[^1]。 对于旧版本的 Excel 用户,则可以通过组合其他函数如 `INDEX` 和 `MATCH` 来模拟这一功能。具体来说,这种方法涉及构建数组公式以排除重复项并仅保留首次出现的条目。 #### 利用 VBA 宏程序 另一种强大的方式是借助 Visual Basic for Applications (VBA) 编写宏脚本来自动化处理过程。一段典型的 VBA 脚本如下所示: ```vba Sub ExtractUniqueValues() Dim dict As Object Set dict = CreateObject("Scripting.Dictionary") Dim rng As Range Set rng = Application.InputBox(Prompt:="Select the range to extract unique values from", Type:=8) Dim cell As Range For Each cell In rng.Cells If Not IsEmpty(cell.Value) Then dict(cell.Value) = True ' Adds item as key; value is irrelevant. End If Next Dim ws As Worksheet Set ws = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count)) ws.Name = "Unique Values" i = 1 For Each Key In dict.Keys ws.Cells(i, 1).Value = Key i = i + 1 Next End Sub ``` 上述代码片段展示了如何利用字典对象存储唯一的键值对从而过滤掉重复记录,并将结果输出至新工作表中[^3]。 另外还有更复杂的场景比如跨多列查找唯一组合的情况也可以通过调整 `.RemoveDuplicates` 方法中的参数轻松完成。 #### 合并唯一值为单字符串 如果目标不仅是找出独立单元格里的独特项目而是希望进一步把这些单独的结果串联成单一文本串的话,那么还可以考虑应用自定义 UDF(User Defined Function)或者依赖现有的插件扩展包来达成目的[^2]。 例如有这样一个简单的例子展示怎样把选定区域内所有的不同数值按逗号分隔开形成一句连续的话语: ```excel =TEXTJOIN(",",TRUE,CUnique(B:B)) ``` 这里调用了名为 CUnique 的第三方附加组件所提供的服务以便简化整个流程同时提高效率. 综上所述,在不同的需求背景下可以选择适合自己的技术手段去解决实际遇到的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值