[BalkanOI 2007] Dream

吐槽一下出题人
没事干嘛把第一行和最后一行单独列出来
非要让人在代码里加一个分讨
写题的时候都无语了
中午题面里的描述也是奇奇怪怪

从整除的角度来思考
我们需要记录的东西就是当前乘积的因数
对于是否整除可以使用gcd来判断
然后我们还需要一个辅助数组来记录某个乘积和k的gcd有多少种方案数
然后每次更新的时候根据辅助数组来更新即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=200+10;
const int N=1001;
int f[maxn][N],now[N],g[N],a[N],b[200010];
int trans[N][N],c[maxn][10010];
int l,t,n,m,p,mod,cnt;
int main(){
    cin>>n>>m>>p>>mod;
    for(int i=1;i<=p;i++)if(!(p%i))a[++cnt]=i,b[i]=cnt;
    for(int i=1;i<=cnt;i++)
    	for(int j=1;j<=cnt;j++)
            trans[i][j]=b[__gcd((int)((ll)a[i]*a[j]%p),p)];
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>c[i][j];
    for(int i=1;i<=n;i++){
        memset(g,0,sizeof(g));
        for(int j=1;j<=m;j++)(g[b[__gcd(c[i][j],p)]]+=1)%=mod;
        for(int j=1;j<=cnt;j++)now[j]=g[j];
        if(1<i&&i<n)
            for(int j=1;j<=cnt;j++)
            	for(int k=1;k<=cnt;k++)
                    if(j==k)(now[trans[j][k]]+=g[j]*(g[j]-1)%mod)%=mod;
                    else(now[trans[j][k]]+=g[j]*g[k]%mod)%=mod;
        for(int j=1;j<=cnt;j++)
            for(int k=1;k<=cnt;k++)
                (f[i][trans[j][k]]+=f[i-1][j]*now[k]%mod)%=mod;
    }
    cout<<f[n][cnt];
}
posted @ 2025-08-19 21:08  zhuoheng  阅读(14)  评论(0)    收藏  举报