T1:math

题目链接:

http://zhengruioi.com/contest/156/problem/471

题解:

先讲讲我的乱搞做法。对于前面70%,我跑了背包。因为背包有后效性...我做了两次,也就是迭代了一下

剩下的30%随机化了一波。就是先把每个数的20以内的倍数暴力的算出来对k取模然后丢到一个大小为k的桶里面去。因为题目就是让你给每个数一个系数,于是我就每次随机两个位置相加判断在模k的意义下是否出现过,如果没有出现过就加入答案中,咳咳重复1e7次即可A掉本题

下面说说题解做法:

$ax+by=z$存在整数解,当且仅当$gcd(a, b)∣z$。

那么,若z可以被凑出,即 $\sum_{i=1}^{n} x_ia_i = z$,当且仅当 $gcd(a_1, a_2,⋯, a_n)∣z$。

因此,答案只能是gcd的整数倍。

但是,这样考虑x有可能是负数,但是在mod k的条件下,我们可以把x调为非负整数。

时间复杂度$O((n + k)logv)$。

乱搞代码

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<vector>
#include<time.h>
using namespace std;

const int N=1e6+15;
int n,k;
int a[N],f[N];
inline int read(){
    char ch=getchar();int s=0,f=1;
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*f;
}
namespace task1
{
    void main()
    {
        for (int i=1;i<=n;i++)
        for (int j=0;!f[1ll*j*a[i]%k];j++) f[1ll*j*a[i]%k]=1; 
        for (int i=1;i<=n;i++)
        {
            for (int j=0;j<=k;j++) f[j]|=f[((j-a[i])%k+k)%k];
            for (int j=0;j<=k;j++) f[j]|=f[((j-a[i])%k+k)%k];
        }
        int s=0;
        for (int j=0;j<k;j++) s+=f[j];
        printf("%d\n",s);
        for (int j=0;j<k;j++) if (f[j]) printf("%d ",j);
    }
}
int gcd(int a,int b) {if (!b) return a;else return gcd(b,a%b);}
namespace task2
{
    void main()
    {
        printf("%d\n",k);
        for (int i=0;i<k;i++) printf("%d ",i);
    }
}
int main()
{
    n=read();k=read();
    for (int i=1;i<=n;i++) a[i]=read()%k;
    for (int i=1;i<=n;i++) if (a[i]==1||gcd(a[i],k)==1) {task2::main();return 0;}
    if (n<=1000) {task1::main();return 0;}
    srand(time(0));
    vector <int> p;
    for (int i=1;i<=n;i++)
    {
        for (int j=0;j<=20;j++) 
        {
            int q=1ll*j*a[i]%k;
            if (!f[q]) 
            {
                p.push_back(q);
                f[q]=1;
            }
        }
    }
    for (int i=1;i<=1e7;i++)
    {
        int si=p.size();
        int l=rand()%si,r=rand()%si;
        if (!f[(p[l]+p[r])%k]) 
        {
            p.push_back((p[l]+p[r])%k);
            f[(p[l]+p[r])%k]=1;
        }
    }
    int s=0;
    for (int j=0;j<k;j++) s+=f[j];
    printf("%d\n",s);
    for (int j=0;j<k;j++) if (f[j]) printf("%d ",j);
    return 0;
}
View Code

相关文章:

  • 2021-07-16
  • 2021-12-03
  • 2021-06-19
  • 2022-12-23
  • 2021-12-19
  • 2022-01-14
  • 2022-01-06
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2021-08-16
  • 2022-03-04
  • 2022-03-03
  • 2021-07-19
  • 2021-09-20
  • 2021-11-18
相关资源
相似解决方案