jzoj3156. 【GDOI2013模拟1】病毒传播

时间:2021-07-29 07:58:31

题意:
村庄里有m个人,初始有一些人感染了病毒。如果第i个人的编号i满足,有一对(a,b)(a是初始病毒感染者编号,b为前一天的感染者编号)使\(a*b mod m =i\),则第i个人会感染病毒。每次感染症状只持续1天(但是可能在几天内会感染多次),问k天以后感染病毒的人的编号
\(m<=1500,k<=1e18\)

我们发现,题目中的“更新操作”满足结合律
于是写一个类似矩阵乘法的东西就行了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll k,m,n,a[100010],bk[1510];
struct no{
    int a[1510];
}x,r;
no mul(no x,no y){
    if(!x.a[0])return y;
    if(!y.a[0])return x;
    memset(bk,0,sizeof(bk));
    no r;memset(r.a,0,sizeof(r.a));
    for(int i=1;i<=x.a[0];i++)
        for(int j=1;j<=y.a[0];j++)
            bk[(x.a[i]*y.a[j])%m]=1;
    for(int i=0;i<m;i++)
        if(bk[i])r.a[++r.a[0]]=i;
    return r;
}
int main(){
    scanf("%lld%lld%lld",&k,&m,&n);
    x.a[0]=n;
    for(int i=1;i<=n;i++)
        scanf("%lld",&x.a[i]);
    while(k){
        if(k&1)r=mul(r,x);
        x=mul(x,x);
        k>>=1;
    }
    for(int i=1;i<=r.a[0];i++)
        printf("%d ",r.a[i]);
}