bzoj4772 顯而易見的數論


題意:http://www.lydsy.com/JudgeOnline/problem.php?id=4772

sol :這個題卡了我一整天QAQ

   出題人簡直喪心病狂,卡內存+卡常數QAQ

   題意就是,給你一個整數,讓你求所有整數划分的方案數的價值和,價值是個函數

   長成這個樣子:

   划分方案數

   然后就是,考慮枚舉pi和pj,如何算這個二元組在整數划分中出現的次數

   記sum[i]為將i進行整數划分的方案數(實際操作時為避免數組下標為負所以將sum反向)

sum[0]=1;
for(int i=1;i<=n;i++)
{
    for(int j=1;j<=n;j++)
    {
        if(i==1||j==1) f[i][j]=1;
        else if(i==j) f[i][j]=(f[i][j-1]+1)%p;
        else if(i<j) f[i][j]=f[i][j-1];
        else f[i][j]=(f[i-j][j]+f[i][j-1])%p;
    }
    sum[i]=f[i][i];
}

   當pi!=pj的時候,枚舉pi和pj出現的次數muli,mulj,那么答案即為ans[pi][pj]+=sum[n-pi*muli-pj*mulj]

   而當pi=pj時,同樣枚舉pi出現的次數,我們要考慮兩兩組合的方案數

     即ans[pi][pi]+=muli*(muli-1)/2*(sum[muli*pi]-sum[(muli+1)*pi])

   然后我到這就不會了QAQ,於是去請教了Nbc和Claris,%%%

   Nbc表示這個題就是個暴力隨便搞搞就行了......我:

   Claris表示其實這個g是個積性函數......我:

   好了這個題可以做了QAQ

   我們考慮g(n)在n為質數的情況下的值為2n-2,所以直接預處理線性篩一發g(x)就行了QAQ

   然后對於那個F(i,j)我們可以預處理一發gcd和pow就可以O(1)做了

   於是我們的做法就是,枚舉不相等的i和j,統計答案

for(int i=1;i<=n;i++)
    for(int j=i+1;j<=n-i;j++)
        for(int muli=1;muli*i+j<=n;muli++)
            for(int mulj=1;mulj*j+muli*i<=n;mulj++)
                ans+=g[a[F(i,j)]]*sum[muli*i+mulj*j]%p,ans%=p;

   然后再枚舉相等的i和j,統計答案

for(int i=1;i<=n;i++)
    for(int muli=1;muli*i<=n;muli++)
        ans=(ans+g[a[F(i,i)]]*muli*(muli-1)/2*(sum[muli*i]-sum[(muli+1)*i]+p))%p;

   然后我們就愉悅的發現他0ms TLE了

   哦....原來是define int long long炸內存了啊QAQ

   簡單的改了改然后交上去,發現他又偷♂稅的T掉了......

   我們發現在統計不相等的i和j時的取模操作太多了QAQ

   於是我們可以手動實現一發取模操作...然而我並不會乘法取模,怎么辦呢?

   我們發現乘法取模是因為乘了一個g[],然而F(i,j)的范圍只有1e5,奧妙重重

   考慮開一個數組Cnt記錄F的每個值的訪問次數,這樣的話在后面一次性統計即可

for(int i=1;i<=n;i++)
  for(int j=i+1;j<=n-i;j++)
    for(int muli=1;muli*i+j<=n;muli++)
      for(int mulj=1;mulj*j+muli*i<=n;mulj++)
        mod(Cnt[F(i,j)],sum[muli*i+mulj*j]);
for(int i=0;i<K;i++) ans+=1LL*g[a[i]]*Cnt[i]%p,ans%=p;

   於是這道題就可以切掉了QwQ

   附上完整代碼

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int p=1e9+7;
const int Mx1=2010;
const int Mx2=1e7+10;
int tp,n,K,a[Mx2],sum[Mx1],f[Mx1][Mx1],gcd[Mx1][Mx1],mul[Mx1][Mx1];
int cnt,ans,pri[Mx2],tmp[Mx2],g[Mx2],b[Mx1];
bool jud[Mx2];
inline void pre()
{
    sum[n]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i==1||j==1) f[i][j]=1;
            else if(i==j) f[i][j]=(f[i][j-1]+1)%p;
            else if(i<j) f[i][j]=f[i][j-1];
            else f[i][j]=(f[i-j][j]+f[i][j-1])%p;
        }
        sum[n-i]=f[i][i];
    }
    g[0]=0,g[1]=1;
    for(int i=2;i<=1e7;i++)
    {
        if(!jud[i]) pri[++cnt]=tmp[i]=i,g[i]=(2*i-2)%p;
        for(int j=1;j<=cnt&&i*pri[j]<=1e7;j++)
        {
            jud[i*pri[j]]=1;
            if(i%pri[j])
                tmp[i*pri[j]]=pri[j],
                g[i*pri[j]]=g[i]*g[pri[j]]%p;
            else
            {
                tmp[i*pri[j]]=tmp[i]*pri[j];
                if(tmp[i]!=i) g[i*pri[j]]=1LL*g[i/tmp[i]]*g[tmp[i]*pri[j]]%p;
                else g[i*pri[j]]=(1LL*g[i]*pri[j]+i*pri[j]-i)%p;
                break;
            }
        }
    }
    for(int i=1;i<=n;i++) gcd[i][0]=gcd[0][i]=gcd[i][i]=i,gcd[1][i]=gcd[i][1]=1;
    for(int i=2;i<=n;i++)
        for(int j=2;j<=i;j++)
        {
            if(!gcd[i][j]) gcd[i][j]=gcd[j][i-j];
            gcd[j][i]=gcd[i][j];
        }
    for(int i=1;i<=n;i++)
    {
        mul[i][0]=1;
        for(int j=1;j<=n;j++) mul[i][j]=(1LL*mul[i][j-1]*i)%K;
    }
}

inline int F(int pi,int pj)
{
    if(tp==1) return 1%K;
    if(tp==2) return (gcd[pi][pj])%K;
    if(tp==3) return (mul[pi][pj]+mul[pj][pi]+(pi^pj))%K;
}

inline void mod(int &x,const int &y){
    x+=y;
    if (x>=p) x-=p;
}

int Cnt[Mx2];
int main()
{
    scanf("%d%d%d",&tp,&n,&K);
    for(int i=0;i<K;i++) scanf("%d",&a[i]);
    pre();
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n-i;j++)
            for(int muli=1;muli*i+j<=n;muli++)
                for(int mulj=1;mulj*j+muli*i<=n;mulj++)
                    mod(Cnt[F(i,j)],sum[muli*i+mulj*j]);
    for(int i=0;i<K;i++) ans+=1LL*g[a[i]]*Cnt[i]%p,ans%=p;
    for(int i=1;i<=n;i++)
    {
        for(int muli=1;muli*i<=n;muli++)
        {
            int Tmp=1LL*muli*(muli-1)/2*(sum[muli*i]-sum[(muli+1)*i]+p)%p;
              mod(ans,1LL*g[a[F(i,i)]]*Tmp%p);
        }
    }
    cout<<ans<<endl;
    return 0;
}

 

   

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM