首页 > 其他分享 >[SDOI2010] 代码拍卖会 题解

[SDOI2010] 代码拍卖会 题解

时间:2023-07-19 16:02:30浏览次数:42  
标签:int 题解 拍卖会 SDOI2010 模数 ans 物品 ll mod

[SDOI2010] 代码拍卖会 题解

题目描述

一个 \(n,n\le10^{18}\) 位数,仅由 \(1\sim9\) 组成,后一位数字一定大于等于前一位数字。

求这些数中可以被 \(m,m\le500\) 整除的有多少,对 \(999911659\) 取模。

解析

这个数一定形如 \(112334455677788999\) 可以把它拆成

\[\begin{aligned} +111111111111111111\\ +1111111111111111& \\ +111111111111111&\\ +1111111111111&\\ +11111111111&\\ +1111111111&\\ +11111111&\\ +111111&\\ +111 \end{aligned} \]

最多有 \(9\) 个 \(11\cdots11\) 组成。

现在问题转换成有 \(10^{18}\) 个物品,价值是 \(11\dots111\) 取模 \(m\) ,选择 \(\le9\) 个求和使得可以整除 \(m\) ,求方案数。

我们可以有一种背包计数的 dp 想法,但看起来 \(10^{18}\) 还是不太行。

我们把每个物品按照对 \(m\) 去模得到的结果分类。

然后记录 \(g[i]\) 表示价值为 \(i\) 的有 \(g[i]\) 种物品。

循环节的计算

那么怎么计算 \(g[]\) 数组呢?

普及组知识?

定义 \(s_i\) 表示 \(i\) 个 \(1\) 连起来形成的数, \(f_i\) 为它在 \(\mod p\) 意义下的值。

如 \(s_5=11111\)

\(f_3=1\mod 5\)

则显然有 \(f_i=(10\times f_{i-1}+1)\%p\)

显然这柿子在 \(2p\) 次迭代内必然会出现循环。

可以把 \(f_i\) 分成三段:

  • 未进入循环段

  • 循环段

  • 不完整循环段

暴力统计 未进入和不完整 的,用循环节搞定循环的就好了。

计数

我们不关心这个物品具体是什么,我们只需要保证物品求和去模之后为 \(0\) 就可以了。

假如 \(m = 19\) 我们只需要:

7 个模数为 1 ,2 个模数为 6,或者 3 个模数为5,4 个模数为 1,\(\cdots\)

这一类的情况都是我们想要的。

总的来说,我们要物品总数 \(\le9\) ,价值和整除 \(m\) 。

我们设 \(f[i][j][s]\) 表示用了价值从 \(1\sim i\) 的物品 ,现在总共放了 \(j\) 个物品,总模数为 \(s\) 的方案数。

答案很显然是:

\[\sum_{j=1}^9 f[m-1][j][0] \]

转移也很简单了。

枚举当前价格为 \(i\) 的物品你会选 \(k\) 个。

转移的最后一维减法是在模意义下的。

\[f[i][j][s]=\sum_{k=0}^{j} f[i-1][j-d][s - d \times i]\times \binom {g[i] + d - 1} {d} \]

最后一个组合数代表着 从 \(g[i]\) 中无序(组合)可重复的选择 \(d\) 个数。

为什么是这个,考虑插板法。

组合数

从 \(m\) 个数 \(a_1,a_2,\cdots,a_m\) 中选 \(k\) 个数,我们令 \(a_i\) 选了 \(t_i\) 次。

相当于解方程 \(t_1 + t_2 + \cdots+t_m=n\) 。

我们把所有的 \(t\) 统一先加上 1,保证没有 0。

现在有 \(m + t\) 个点,我们用 \(m - 1\) 隔板在中间去插,首尾默认有两个隔板,会得到 m 个区间。每个区间就代表着 \(t_1\) 的取值。

所以 \(m-1\) 个隔板有 \(m + t - 1\) 种位置可以插入。

\[\binom {m+t-1}{m-1} = \binom {m+t-1}{t} \]

上图代表着从 5 个数中选 4 个的其中一种方案。

温馨提示

因为猪猪不可以选0,所以第一个一定是 \(\underset{n个1}{111\cdots111}\)。那我们只需要找 \(8\) 个,并且最后取答案的模数 + \(\underset{n个1}{111\cdots111}\) = 0。

我代码中的因为模数 \(0\sim{m-1}\) ,初始值就需要设在 \(f[-1][0][0]\) 中,不合法,我就把第一位全部往后移动了一位。

代码

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
const int mod = 999911659;
ll n,g[510],f[510][10][510];
int p,d,jl;
vector<int> v[510];
ll qpow(ll x,int k){
    ll ans = 1;
    while(k){
        if(k & 1) ans = ans * x % mod;
        x = x * x % mod;
        k >>= 1;
    }
    return ans;
}
ll C(ll n ,ll m){
    if(m < 0)    return 0;
    ll fz = 1 ,fm = 1;
    for(ll i = 1; i <= m; ++i){
        fz = fz * (n - i + 1) % mod;
        fm = fm * i % mod;
    }
    return fz * qpow(fm ,mod - 2) % mod;
}
void pre(){
    int now = 0;
    for(int i = 1; i <= 2 * p; ++i){
        now = (now * 10 + 1) % p;
        v[now].push_back(i);
    }
    for(int i = 0; i < 500; ++i){
        g[i] = 0;
        if(v[i].size() == 0 || v[i][0] > n) continue;
        if(v[i].size() == 1){
            g[i] = v[i].size();
            continue;
        }
        d = v[i][1] - v[i][0];
        g[i] = (((n - v[i][0]) / d) + 1 ) % mod;
        if((n - v[i][0]) % d == 0){
            jl = i;
        }
    }
}
void op(){
    for(int i = 0; i <= p ; ++i) f[i][0][0] = 1;
    for(int i = 1; i <= p; ++i){
        for(int j = 1; j <= 8; ++j){
            for(int k = 0; k <= 1ll * j; ++k){
                ll mul = C(g[i - 1] + k - 1,k);
                if(k > 0 && g[i - 1] == 0) break;
                for(int s = 0; s < p; ++s){//这里换一下dp顺序先枚举 k 在枚举 d 不然算组合数要超时
                    f[i][j][s] += mul * f[i - 1][j - k][(s - k * (i - 1) % p + p) % p] % mod;
                    f[i][j][s] %= mod;
                }
            }
        }
    }
}
void output(){
    ll ans = 0;
    for(int i = 0; i <= 8; ++i){
        ans = (ans + f[p][i][(p - jl) % p]) % mod;
    }
    cout<<ans;
}
int main(){
    cin>>n>>p;
    pre();
    op();
    output();
    return 0;
}

标签:int,题解,拍卖会,SDOI2010,模数,ans,物品,ll,mod
From: https://www.cnblogs.com/hfjh/p/17565840.html

相关文章

  • 黑群晖NAS7.0+安装问题解决经验分享
    感谢网上各种帖子及分享,为大家提供一个解决思路,机器配置多种多样,解决办法也仅供参考;1、引导后,无法找到群晖  遇到无法找到群晖的情况,首先要排除引导不兼容的问题。在bios中分别设置传统引导模式和UEFI引导模式尝试启动试下。最新版7.0.1的引导文件是两种启动方式都支持的,理......
  • 题解 [USACO18JAN] MooTube G
    题目链接可以发现,对于一个固定的\(k\),所有边权小于\(k\)的边对答案是没有贡献的,因为一条边的相关性是最小相关性,这也意味着我们不能从\(<k\)的边到达其他的点。由于本题有多组询问,所以对于没有用的边,将其看做被删除,有用的边,将其看做被插入。考虑到本题实际上要维护连通块......
  • 洛谷 P1122 最大子树和 题解
    一道入门的树形DP。首先我们对于数据进行有序化处理,这便于我们利用数据结构特点(可排序性)来发觉数据性质(有序、单调、子问题等等性质),以便于后续的转化、推理和处理。有序化可以“转化和创造”性质首先将视角从无根树切换为有根树,这样我们就可以得到一个带有最优子结构、无后效性......
  • HDU 5492 Find a path 题解
    Description在矩阵中,找一条到从\((1,1)\)到\((n,m)\)(只能向上,右走)的路径,使路径上方差最小。输出方差平方乘\(n+m-1\)的结果。对于所有数据,\(1\leqn,m,A_{i,j}\leq30\)。Solution设路径上的数为\(A_{1},A_{2},A_{3},\cdots,A_{n+m-1}\),\(\overline{A}\)为其平均数,则答......
  • 题解 序列合并
    题目链接首先不难想到,最小数的一定是\(a_1+b_1\),次小的数是\(a_1+b_2\)和\(a_2+b_1\)中小的。得出结论,若\(a_i+b_j\)是第\(k\)小,那么\(a_{i+1}+b_j\)和\(a_i+b_{j+1}\)有可能成为第\(k+1\)小。这是一个很优秀的性质,这意味着我们可以通过最小值推出次小值,再通过......
  • “范式杯”2023牛客暑期多校训练营1 蒻蒟题解
    A.AlmostCorrect题意:给定一个01串,要求构造一系列排序操作(xi,yi),使得经过这些排序操作后可以使与给定01串等长的所有其他01串完全排好序,而给定的01串无法完全排好序Solution构造题我们考虑到对0和1的位置进行统计,统计得出最左边的1的位置为l,最右边的0的位置为r我们进行三次......
  • 【SP21463 题解】
    Descirption给定\(n\timesm\)的矩阵,求最大子矩阵的面积满足每一行每一列都构成等差数列。Solution我们另\(up_{i,j}\)表示最小的\(k\)满足\((i,k),(i,k+1),\cdots,(i,j)\)构成等差数列,可以用\(\mathcalO(nm)\)求出。对于一个矩阵的左上角\((a,b)\),右下......
  • BZOJ 1461 题解
    考虑设计一个哈希函数\(hash(x)=f(x)\timesbase^x\)。其中\(f(x)\)表示\(\sum_{j=1}^{i-1}[j<i]\)。然后类似于滑动窗口计算区间哈希值,加入一个数就计算贡献,减去一个数就计算这个数产生了贡献,两个东西都可以树状数组维护,那么愉快做完了。#include<bits/stdc++.h>#de......
  • P5494 题解
    来一发\(O(\logn)\)线性空间的解法。考虑通过只维护线段树叶子节点的虚树的方法压缩空间,考虑记录下每个节点的编号,然后通过异或完求最低位的\(1\)的方式求出LCA的深度,然后记录下LCA右端点的编号。在回收节点的时候可以释放储存右端点编号的空间,但是这里为了方便就不这样......
  • UNR #7 Day2 T1 火星式选拔题解
    放一个比赛链接先考虑打完暴力后\(k=1\)的特殊性质。当队列容量为\(1\)时,队中的人\(i\)会被第一个满足\(i\leqj\)且\(b_i\leqa_j\)的人淘汰,并且队列中的人会变成\(j\),考虑倍增加速这个过程,令\(f_{i,j}\)表示第\(i\)个人进队后淘汰过程发生\(2^j\)次后队......