日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

2014.9.13模拟赛【数位和乘积】

發布時間:2023/12/10 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2014.9.13模拟赛【数位和乘积】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

數位和乘積(digit.cpp/c/pas)

【題目描述】

一個數字的數位和乘積為其各位數字的乘積。求所有的N位數中有多少個數的數位和乘積恰好為K。請注意,這里的N位數是可以有前導零的。比如01,02視為二位數,但是他們的數位和乘積都是0。

?

【輸入格式】

一行兩個整數N,K

?

【輸出格式】

一個行一個整數表示結果。

?

【樣例輸入】

2 3

【樣例輸出】

2

【樣例輸入2】

2 0

【樣例輸出2】

19

?

【數據范圍】

對于20%:N <= 6。

對于50%:N<=16

存在另外30%:K=0。

對于100%:N?<= 50,0 <= K <= 10^9。


……這題要分類討論

1、k==0時,答案是n位數中至少有一個的方案數。根據容斥原理就是總的方案數-n位數中一個0也沒有的方案數,即10^n-9^n。因為n<=50,要高精度乘、減

2、k!=0時,先分解質因數。如果有2、3、5、7以外的質因數,肯定無解。因為k是各位乘起來的積,不可能出現有一位是11、13之類

然后保存2、3、5、7的指數(設為m2、m3、m5、m7)

令f[i][j][k][l][m]表示前i位湊出j個2、k個3、l個5、m個7的方案數

然后轉移就是枚舉第i位是1到9的轉移(好麻煩啊不想寫在這里了……看我代碼)

根據計算因為k<=10e,所以只要開數組f[55][30][20][14][12]就差不多了

這樣每個f依然要高精度……MLE啦……所以還要滾動數組或者像一維背包dp的做法一樣倒著for就可以省掉第一維

(哇啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊因為我的高精數組清0剛好少算一位就wa了只有90不開心啊啊啊啊啊啊啊啊啊啊)

#include<cstdio> #include<cstring> #define mx 50 #define LL long long struct gaojing{int len;int a[mx+10]; }f[30][20][14][12]; int n,k; inline int max(int a,int b){return a>b?a:b;} inline int min(int a,int b){return a<b?a:b;} inline void set0(gaojing &s) {s.len=0;for (int i=1;i<mx+5;i++)s.a[i]=0; } inline void put(gaojing a) {for (int i=a.len;i>=1;i--)printf("%d",a.a[i]);printf("\n"); } inline void addi(gaojing a,gaojing b,gaojing &c) {set0(c);int maxlen=max(a.len,b.len); for (int i=1;i<=maxlen;i++) { c.a[i]=c.a[i]+a.a[i]+b.a[i]; if (c.a[i]>=10) { c.a[i+1]+=c.a[i]/10;c.a[i]%=10;}} c.len=maxlen+1; while (!c.a[c.len]&&c.len>1) c.len--; } inline void jian(gaojing a,gaojing b,gaojing &c) {set0(c);for (int i=1;i<=b.len;i++){c.a[i]=a.a[i]-b.a[i];if (c.a[i]<0){c.a[i]+=10;int now=i+1;while (!a.a[now]){a.a[now]=9;now++;}a.a[now]--;}}for (int i=b.len+1;i<=a.len;i++)c.a[i]=a.a[i];c.len=a.len;while (c.a[c.len]==0&&c.len>1)c.len--; } inline void mult(gaojing a,gaojing b,gaojing &c) {set0(c);for(int i=1;i<=a.len;i++)for (int j=1;j<=b.len;j++)c.a[i+j-1]+=a.a[i]*b.a[j];int mxlen=a.len+b.len+3;for (int i=1;i<=mxlen;i++){c.a[i+1]+=c.a[i]/10;c.a[i]%=10;}while (c.a[mxlen]==0)mxlen--;c.len=mxlen; } const int prime[5]={0,2,3,5,7}; int num[5]; int main() {freopen("digit.in","r",stdin);freopen("digit.out","w",stdout);scanf("%d%d",&n,&k);if (k==0)//若k=0,方案數為10^n-9^n {gaojing sum;set0(sum);gaojing tomul;set0(tomul);gaojing decs;set0(decs);sum.len=1;sum.a[1]=1;tomul.len=1;tomul.a[1]=9;decs.len=n+1;decs.a[n+1]=1;for(int i=1;i<=n;i++)mult(sum,tomul,sum);jian(decs,sum,sum);put(sum);return 0;}for (int i=1;i<=4;i++)while (k%prime[i]==0){k/=prime[i];num[i]++;}if (k!=1){printf("0");return 0;}f[0][0][0][0].a[1]=1;f[0][0][0][0].len=1;for (int i=0;i<=num[1];i++)for (int j=0;j<=num[2];j++)for (int k=0;k<=num[3];k++)for (int l=0;l<=num[4];l++)f[i][j][k][l].len=1;for (int i=1;i<=n;i++){int m2=min(num[1],3*i);int m3=min(num[2],2*i);int m5=min(num[3],i);int m7=min(num[4],i);for (int j=m2;j>=0;j--)for (int k=m3;k>=0;k--)for (int l=m5;l>=0;l--)for (int m=m7;m>=0;m--){if (j>=1)addi(f[j][k][l][m],f[j-1][k] [l] [m] ,f[j][k][l][m]);//2if (k>=1)addi(f[j][k][l][m],f[j] [k-1][l] [m] ,f[j][k][l][m]);//3if (j>=2)addi(f[j][k][l][m],f[j-2][k] [l] [m] ,f[j][k][l][m]);//4if (l>=1)addi(f[j][k][l][m],f[j] [k] [l-1][m] ,f[j][k][l][m]);//5if (j&&k)addi(f[j][k][l][m],f[j-1][k-1][l] [m] ,f[j][k][l][m]);//6if (m>=1)addi(f[j][k][l][m],f[j] [k] [l] [m-1],f[j][k][l][m]);//7if (j>=3)addi(f[j][k][l][m],f[j-3][k] [l] [m] ,f[j][k][l][m]);//8if (k>=2)addi(f[j][k][l][m],f[j] [k-2][l] [m] ,f[j][k][l][m]);//9}}put(f[num[1]][num[2]][num[3]][num[4]]); }

  

轉載于:https://www.cnblogs.com/zhber/p/4035998.html

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的2014.9.13模拟赛【数位和乘积】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。