题目大意
有一个大小为 N ∗ N N*N N∗N的矩阵,一开始矩阵内每一个数都是1,每一次变换后坐标为 ( i , j ) (i,j) (i,j)内的数会累加到 ( f ( i ) , f ( j ) ) (f(i),f(j)) (f(i),f(j)),其中 f ( x ) f(x) f(x)为各位数的累积(如果 f ( x ) = 0 f(x)=0 f(x)=0,那么直接消失)。问一次变换后矩阵内前 K K K大的数之和。
N ≤ 1 0 12 , K ≤ 1 0 6 N\le10^{12},K\le10^6 N≤1012,K≤106
解题分析
首先定义 d i d_i di为在 [ 1 , N ] [1,N] [1,N]内乘积为i的数的个数,那么 ( i , j ) (i,j) (i,j)的个数为 d i ∗ d j d_i*d_j di∗dj,所以先算出 d i d_i di
由于 f ( x ) f(x) f(x)函数累积的数都小于10,所以对于任何一个 f ( x ) f(x) f(x),最多只有2,3,5,7四个素数,一枚举发现这种数在 1 0 12 10^{12} 1012内只有14672个,所以用数位DP累加答案,然后利用堆优化就好了。
示例代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=15000,flg[4]={2,3,5,7},tt=1e9+7;
int m,q,c[20],pos[maxn],len,ans;
LL n,a[4][50],b[maxn],nxt[maxn][10],f[20][maxn][2],d[maxn];
int _find(LL x){
int L=1,R=m,mid;
while (L<=R){
int mid=L+(R-L>>1);
if (b[mid]==x) return mid;
if (b[mid]<x) L=mid+1; else R=mid-1;
}
return 0;
}
struct data{
LL te; int x;
data (LL te=0,int x=0):te(te),x(x){}
bool operator < (const data b)const{return te>b.te;}
}hep[maxn];
void Hput(data a){
hep[++len]=a;
for (int son=len;hep[son]<hep[son>>1]&&son!=1;son>>=1) swap(hep[son],hep[son>>1]);
}
data Hget(){
data ans=hep[1]; hep[1]=hep[len--];
for (int fa=1,son;(fa<<1)<=len;fa=son){
son=fa<<1; if (son<len&&hep[son|1]<hep[son]) son++;
if (hep[son]<hep[fa]) swap(hep[son],hep[fa]); else break;
}
return ans;
}
void makep(){
bool vs[4]; memset(vs,1,sizeof(vs)); int te=4;
for (int j=0;j<4;j++) a[j][0]=a[j][1]=1;
while (te){
for (int j=0;j<4;j++)
if (a[j][a[j][0]]*flg[j]<=n){a[j][a[j][0]+1]=a[j][a[j][0]]*flg[j]; a[j][0]++;}
else {te-=vs[j]; vs[j]=0;}
}
for (int i=1;a[0][i]<=n&&i<=a[0][0];i++)
for (int j=1;a[0][i]*a[1][j]<=n&&j<=a[1][0];j++)
for (int k=1;a[0][i]*a[1][j]*a[2][k]<=n&&k<=a[2][0];k++)
for (int p=1;a[0][i]*a[1][j]*a[2][k]*a[3][p]<=n&&p<=a[3][0];p++)
b[++m]=a[0][i]*a[1][j]*a[2][k]*a[3][p];
sort(b+1,b+m+1); m=unique(b+1,b+m+1)-b-1;
for (int i=1;i<=m;i++)
for (int j=1;j<10;j++) nxt[i][j]=_find(b[i]*j);
LL x=n; do{c[++c[0]]=x%10; x/=10;}while(x);
}
int main()
{
freopen("gold.in","r",stdin);
freopen("gold.out","w",stdout);
scanf("%lld%d",&n,&q); makep(); f[c[0]+1][1][1]=1;
for (int i=c[0];i;i>1?f[i--][1][0]++:i--)
for (int t=0;t<2;t++)
for (int j=1;j<=m;j++)
for (int k=1,mx=(t?c[i]:9);k<=mx;k++)
if (nxt[j][k]) f[i][nxt[j][k]][t&&k==mx]+=f[i+1][j][t];
for (int i=1;i<=m;i++) d[i]=-f[1][i][0]-f[1][i][1]; sort(d+1,d+m+1);
ans=len=0; for (int i=1;i<=m;i++) Hput(data(d[i]*d[pos[i]=1],i));
while (q--){data p=Hget(); int x=p.x; ans=(ans+p.te%tt)%tt; Hput(data(d[x]*d[++pos[x]],x));}
printf("%d",ans);
return 0;
}