潜龙未见静水流,沉默深藏待时秋。一朝破空声势振,惊世骇俗展雄猷。
随笔 - 80, 文章 - 0, 评论 - 2, 阅读 - 1991

HDU7217 Counting Good Arrays 题解

目录

题目描述

T 组数据,求满足以下条件的正整数序列 a 个数,对 109+7 取模:

  • 序列长度 kn
  • akm
  • 1ik1 ,有 aiai+1

数据范围

  • 1T103,1n,m109

保证 max(n,m)>108 的数据至多 1 组, max(n,m)>106 的数据至多 10 组, max(n,m)>103 的数据不超过 50 组。

时间限制 6s ,空间限制 512MB

分析

如果直接枚举 ak 然后推式子,然后就会像博主一样发现式子没法化简,于是进了死胡同。。。

注意到 ai 大部分是相同的,不同的值不超过 logm 个。

因此,补充定义 a0=1 ,令 bi=aiai1 ,问题转化为对序列 b 计数。

由于 b>1 的项不超过 logm ,容易想到先对这些项按照相对位置 dp ,最后将 1 插入其中,乘上一个组合数的系数即可。

dpi,j 表示填了 i>1 的数, k=1ibk=j 的方案数。

接下来又是一个套路:把第二维记成 mj从而把第二维的状态数从 m 压到 2m

转移方程 dpi1,jdpi,jk ,同样可以整除分块优化。

每一层的转移代价:

i=1mO(i+mi)=O(m34)

但是 O(logmm34) 仍然过不去。

还有最后一个小优化,由于每一轮至少除以 2 ,所以第 i 轮的枚举上界为 m2i1

时间复杂度降至:

O(i=1logm(m2i1)34)=O(m34)

可以通过,注意为了卡常需要对这 2m 个数预处理整除分块。

#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pii pair<int,int>
using namespace std;
const int maxn=1e5,mod=1e9+7;
int m,n,t,sq,cnt,res;
int c[maxn],id[2][maxn];
int dp[30][maxn];
vector<pii> vec[maxn];
int qpow(int a,int k)
{
    int ans=1;
    while(k)
    {
        if(k&1) ans=1ll*ans*a%mod;
        a=1ll*a*a%mod,k/=2;
    }
    return ans;
}
int get_id(int x)
{
    return x<=sq?id[0][x]:id[1][m/x];
}
void add(int &x,long long y)
{
    x=(x+y)%mod;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m),sq=sqrt(m),cnt=0;
        for(int l=1,r=0;l<=m;l=r+1) r=m/(m/l),c[++cnt]=m/l;
        sort(c+1,c+cnt+1);
        for(int i=1;i<=cnt;i++)
        {
            int x=c[i];
            if(x<=sq) id[0][x]=i;
            else id[1][m/x]=i;
            vec[i].clear();
            for(int l=2,r=0;l<=x;l=r+1)
            {
                r=x/(x/l);
                vec[i].push_back(mp(get_id(x/l),r-l+1));
            }
        }
        for(int j=1;j<=cnt;j++) dp[0][j]=0;
        dp[0][get_id(m)]=1,res=n;///b[i]全为1的序列有n个
        for(int i=1,v=n+1;1<<i<=m;i++)
        {///v=c(n+1,i+1)
            v=v*(n+1ll-i)%mod*qpow(i+1,mod-2)%mod;
            for(int j=get_id(m>>i);j>=1;j--) dp[i][j]=0;
            for(int j=get_id(m>>(i-1));j>=1;j--)
                for(auto p:vec[j])
                    add(dp[i][p.fi],1ll*dp[i-1][j]*p.se);
            for(int j=get_id(m>>i);j>=1;j--) add(res,1ll*dp[i][j]*v);
        }
        printf("%d\n",res);
    }
    return 0;
}

posted on   peiwenjun  阅读(2)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示