【JZOJ3216】【SDOI2013】淘金

╰( ̄▽ ̄)╭

小 Z在玩一个 叫做《淘金者》的游戏。游戏的世界是一个 二维坐标 。X轴、Y轴坐标范围均为1..N。初始的时候,所有的整数坐标点上均有一块金子,共 N*N 块。

一阵风吹过, 金子的位置发生了一些变化。细心的小Z发现, 初始 在(i, j) 坐标 处的金子会变到 (f(i),f(j))坐标 处。其中f(x)表示 x各位数字的乘积 ,例如 ,例如 f(99)=81,f(12)=2,f(10)=0。如果金子变化后的坐标不在 1..N 的范围内,我们认为这块金子已经 被移出游戏。 同时可以发现, 对于变化之后的游戏局面, 某些 坐 标上的金子数量可能 不止一块 ,而另外一些坐标上可能已经没有金子 。这次变化 之后, 游戏将不会再对 金子的位置和数量进行改变,玩家可以开始采集工作。

小 Z很懒 ,打算 只进行 只进行 K次采集 。每次采集可以得到某 一个坐标上的所有 金子 ,采集之后该坐标上的金子数变为 0。

现在小 Z希望知道,对于变化之后的游戏局面,在采集次数为K的前提下, 最多可以采集到少块金子?

答案可能很大,小 Z希望得到1000000007 (10^ 9+7) 取模之后的答案。
这里写图片描述

(⊙ ▽ ⊙)

横纵坐标可以分开讨论,
为什么?
f() 函数只与其中某一个坐标有关。


然后还要注意到一个性质:
由于 f() 只会是 0..9 的数之积,所以质因子只会有 2,3,5,7
这个性质保证了,不同的积不会超过 50000 个,并且可以利用数位动态规划预处理出:
这些积分别出现多少次。


现在考虑使用数位动态规划求出这些积分别出现多少次 a[]
fi,j,k,l,o,p 表示,填了 i 位数,并且积为2j3k5l7o,且当前的 i 位数是否小于n的前 i 位(小于等于时p=0,否则 p=1 )。
容易转移;
并且也很容易得出每个积分别出现多少次。(满足条件的 fi,j,k,l,o,p 则对 a[2j3k5l7o] 贡献)


知道了 a[] 后,原问题变成找出前 k 最大的a[i]a[j]
做法:
首先对 a[] 从大到小排序,然后先把所有 a[i]a[1] (i[1,len(a[])]) 放入线段树的对应位置;
显然对线段树进行 k 次最值查询;
每次查询后得到最值的位置,把这一位第二项的a[]往后取一位。

( ̄~ ̄)

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<math.h>
#define ll long long
using namespace std;
const char* fin="ex3216.in";
const char* fout="ex3216.out";
const ll inf=0x7fffffff;
const ll maxn=60007,mo=1000000007,maxh=999997,maxt=maxn*8;
ll n,m,i,j,k,l,o,p,index,J,K,L,O,P;
ll A[maxn],len,ans;
ll f[14][40][26][20][15][2],a[40][26][20][15];
struct node{
    ll x,y;
}b[maxn];
bool cmp(node a,node b){
    return a.y>b.y;
}
ll h[maxh],d[maxh],num;
ll hash(ll x){
    ll k=x%maxh;
    while (h[k] && h[k]!=x) k=(k+1)%maxh;
    return k;
}
ll c[maxt],cc[maxt];
void plant(ll l,ll r,ll t){
    ll mid=(l+r)/2;
    if (l==r){
        cc[t]=1;
        c[t]=b[l].y*b[1].y;
        return;
    }
    plant(l,mid,t*2);
    plant(mid+1,r,t*2+1);
    c[t]=max(c[t*2],c[t*2+1]);
}
ll getmax(ll l,ll r,ll t){
    ll mid=(l+r)/2,k;
    if (l==r){
        k=c[t];
        c[t]=b[l].y*b[++cc[t]].y;
        return k;
    }
    if (c[t*2]>c[t*2+1]) k=getmax(l,mid,t*2);
    else k=getmax(mid+1,r,t*2+1);
    c[t]=max(c[t*2],c[t*2+1]);
    return k;
}
int main(){
    char ch=getchar();
    n=0;
    while (ch<='9' && ch>='0') A[++len]=ch-'0',n=n*10+ch-'0',ch=getchar();
    for (i=1;i<=len/2;i++) swap(A[i],A[len-i+1]);
    scanf("%lld",&m);
    f[0][0][0][0][0][0]=1;
    a[0][0][0][0]=1;
    for (j=0;j<40;j++)
        for (k=0;k<26;k++)
            for (l=0;l<20;l++)
                for (o=0;o<15;o++){
                    if (j) a[j][k][l][o]=a[j-1][k][l][o]*2;
                    else if (k) a[j][k][l][o]=a[j][k-1][l][o]*3;
                    else if (l) a[j][k][l][o]=a[j][k][l-1][o]*5;
                    else if (o) a[j][k][l][o]=a[j][k][l][o-1]*7;
                    if (a[j][k][l][o]>n) a[j][k][l][o]=n+1;
                }
    for (i=0;i<=len;i++)
        for (j=0;j<40;j++)
            for (k=0;k<26;k++)
                for (l=0;l<20;l++)
                    for (o=0;o<15;o++)
                        for (p=0;p<2;p++){
                            if (i<len)
                                for (index=1;index<=9;index++){
                                    ll tmp=index;
                                    J=K=L=O=P=0;
                                    if (index>A[i+1]) P=1;
                                    else if (index==A[i+1]) P=p;
                                    while (tmp%2==0) tmp/=2,J++;
                                    while (tmp%3==0) tmp/=3,K++;
                                    while (tmp%5==0) tmp/=5,L++;
                                    while (tmp%7==0) tmp/=7,O++;
                                    f[i+1][j+J][k+K][l+L][o+O][P]=(f[i+1][j+J][k+K][l+L][o+O][P]+f[i][j][k][l][o][p])%mo;
                                }
                            if (f[i][j][k][l][o][p]>0 && i>0 && (i<len || !p)){
                                if (a[j][k][l][o]>n){
                                    continue;
                                }
                                ll tmp=hash(a[j][k][l][o]);
                                if (!h[tmp]){
                                    h[tmp]=a[j][k][l][o];
                                    b[d[tmp]=++num].x=a[j][k][l][o];
                                }
                                b[d[tmp]].y+=f[i][j][k][l][o][p];
                            }
                        }
    sort(b+1,b+num+1,cmp);
    plant(1,num,1);
    for (i=1;i<=m;i++) ans=(ans+getmax(1,num,1))%mo;
    printf("%lld",ans);
    return 0;
}

(⊙v⊙)

1.对于 f(x) 这种一元函数,可以单独考虑和讨论。
2.对积的质因子敏感,例如本题,只有 2,3,5,7 这四个质因子。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值