HDU7217 Counting Good Arrays 题解
目录
题目描述
组数据,求满足以下条件的正整数序列 个数,对 取模:
- 序列长度 。
- 。
- ,有 。
数据范围
- 。
保证 的数据至多 组, 的数据至多 组, 的数据不超过 组。
时间限制 ,空间限制 。
分析
如果直接枚举 然后推式子,然后就会像博主一样发现式子没法化简,于是进了死胡同。。。
注意到 大部分是相同的,不同的值不超过 个。
因此,补充定义 ,令 ,问题转化为对序列 计数。
由于 中 的项不超过 ,容易想到先对这些项按照相对位置 ,最后将 插入其中,乘上一个组合数的系数即可。
表示填了 个 的数, 的方案数。
接下来又是一个套路:把第二维记成 。从而把第二维的状态数从 压到 。
转移方程 ,同样可以整除分块优化。
每一层的转移代价:
但是 仍然过不去。
还有最后一个小优化,由于每一轮至少除以 ,所以第 轮的枚举上界为 。
时间复杂度降至:
可以通过,注意为了卡常需要对这 个数预处理整除分块。
#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;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/16567405.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具