3.29省选模拟赛 除法与取模 dp+组合计数
LINK:除法与取模

鬼题。不过50分很好写。考虑不带除法的时候 其实是一个dp的组合计数。
考虑带除法的时候需要状压一下除法操作。
因为除法操作是不受x的大小影响的 所以要状压这个除法操作。
直接采用二进制状压是不明智的 2的个数最多为13个 2^13也同样到达了1e4的复杂度。
考虑 hash状压 即 2的个数有x个 那么我们就有状态w表示2还有x个。
这样做的原因是把一些相同的东西给合并起来 而并非分散开来。即有多个2直接记录有多少个即可。
可以发现 这样做不同的除数最多只有5个 状态量较少。
如何hash 考虑采用P进制版本的hash 这样寻找下一个决策什么的也很方便。
如:对于第i个数 进制为(当前个数+1) 这样不需要取模我们的状态量也只有不到100.
可以发现这样的hash不重不漏 缺点是 我们需要知道某个状态代表的是什么意思 去掉某个值后 得到的状态会是什么。
这样做x状态数状态转移+x状态x当前的值.
前者复杂度极低 后者 考虑第一步做的时候 x会除以2所以一半都不需要枚举了 且后面的那个x当前的值也会降低一半 一下就变成了50005000状态的dp了。
第二部做的时候还会除以2 可以发现无效的状态很多我们对于无效的状态不枚举转移即可。
(题解上说是有一个1/16的常数 所以可以通过此题。
dp的时候转移比较ex 值得注意的是 %一个数字或者除以一个数字的时候 如果有重复的存在必须要处理一下相对的关系。
前者 要乘以h[w]//w出现了多少次 因为取模过后剩余的数字被安排过了。那些数字之间不存在先后 因为是排列过的。
后者 发现此时的选择也同样有g[j][w]种 要乘上这个东西的方案。
hash的时候要注意 某个数的0的个数时的状态表示。dp的时候注意两层循环都要倒序枚举。
一道非常优异的dp题目。
const int MAXN=200010,maxn=10010;
int a[MAXN],b[MAXN],q[MAXN],c[MAXN],w[MAXN],p[MAXN],vis[MAXN];
ll fac[MAXN<<1],inv[MAXN],in[MAXN],f[maxn][110];
int g[MAXN][10],v[MAXN],h[MAXN];
int n,m,maxx,s,top,sum,tot;
inline ll ksm(ll b,int p)
{
ll cnt=1;
while(p)
{
if(p&1)cnt=cnt*b%mod;
b=b*b%mod;p=p>>1;
}
return cnt;
}
inline void prepare()
{
fac[0]=1;in[1]=1;
rep(1,maxx,i)
{
fac[i]=fac[i-1]*i%mod;
if(i!=1)in[i]=(mod-mod/i)*in[mod%i]%mod;
}
inv[maxx]=ksm(fac[maxx],mod-2);
fep(maxx-1,0,i)inv[i]=inv[i+1]*(i+1)%mod;
}
inline void get_state()
{
int ww=0;
rep(1,sum,i)ww=ww*(w[i]+1)+q[i];
tot=max(tot,ww);
rep(1,sum,i)g[ww][i]=q[i],v[ww]+=q[i];
}
inline void dfs(int x)
{
if(x==sum+1)
{
get_state();
return;
}
rep(0,w[x],i)
{
q[x]=i;
dfs(x+1);
}
}
int main()
{
freopen("1.in","r",stdin);
get(s);get(n);get(m);maxx=n+m;
prepare();
rep(1,n,i)
{
get(a[i]);
if(a[i]>s){putl(fac[n+m]);return 0;}
}
ll ww=1;
rep(1,n,i)
{
if(a[i]>1)q[++top]=a[i];
ww=ww*a[i];
if(ww>s){putl(fac[n+m]);return 0;}
}
sort(q+1,q+1+top);
rep(1,top,i)
{
if(q[i]==q[i-1])++w[sum],++i;
if(i<=top)c[++sum]=q[i],++w[sum];
}
p[sum]=1;
fep(sum-1,1,i)p[i]=p[i+1]*(w[i]+1);
dfs(1);//整理状态
rep(1,m,i)get(b[i]),++vis[min(b[i],s+1)],++h[b[i]];
rep(1,s+1,i)vis[i]+=vis[i-1];
f[s][tot]=fac[n+m]*inv[n+m-(vis[s+1]-vis[s])-(n-top)]%mod;
fep(s,0,i)
{
//if(i==0)cout<<"www"<<endl;
fep(tot,0,j)
{
if(!f[i][j])continue;
//枚举要取模的数字.
rep(1,i,k)
{
if(!h[k])continue;
//当前还有数字为 v[j]+vis[i]-1
//剩余有效数字为 v[j]+vis[i%k]
f[i%k][j]=(f[i%k][j]+h[k]*f[i][j]%mod*fac[v[j]+vis[i]-1]%mod*inv[v[j]+vis[i%k]]%mod)%mod;
}
rep(1,sum,k)//枚举要除以的数字.
{
if(g[j][k])
{
//当前还有数字为 v[j]-1+vis[i]
//剩余有效数字为 v[j]-1+vis[i/c[k]]
f[i/c[k]][j-p[k]]=(f[i/c[k]][j-p[k]]+g[j][k]*f[i][j]%mod*fac[v[j]-1+vis[i]]%mod*inv[v[j]-1+vis[i/c[k]]]%mod)%mod;
}
}
}
}
/*fep(s,0,i)
{
cout<<i<<' '<<"www"<<' ';
fep(tot,0,j)
cout<<f[i][j]<<' ';
cout<<endl;
}*/
putl(f[0][0]);
return 0;
}
3.29省选模拟赛 除法与取模 dp+组合计数的更多相关文章
- 6.29 省选模拟赛 坏题 AC自动机 dp 图论
考场上随手构造了一组数据把自己卡掉了 然后一直都是掉线状态了. 最后发现这个东西不是subtask -1的情况不多 所以就没管无解直接莽 写题有点晚 故没调出来.. 考虑怎么做 容易想到建立AC自动机 ...
- 5.29 省选模拟赛 树的染色 dp 最优性优化
LINK:树的染色 考场上以为这道题要爆蛋了 没想到 推出正解来了. 反正是先写了爆搜的 爆搜最近越写越熟练了 容易想到dp 容易设出状态 f[i][j]表示以i为根的子树内白色的值为j此时黑色的值怎 ...
- 5.29 省选模拟赛 波波老师 SAM 线段树 单调队列 并查集
LINK:波波老师 LINK:同bzoj 1396 识别子串 不过前者要求线性做法 后者可以log过.实际上前者也被我一个log给水过了. 其实不算很水 我自认跑的很快罢了. 都是求经过一个位置的最短 ...
- codehunter 「Adera 6」杯省选模拟赛 网络升级 【树形dp】
直接抄ppt好了--来自lyd 注意只用对根判断是否哟留下儿子 #include<iostream> #include<cstdio> using namespace std; ...
- 5.4 省选模拟赛 修改 线段树优化dp 线段树上二分
LINK:修改 题面就不放了 大致说一下做法.不愧是dls出的题 以前没见过这种类型的 不过还是自己dp的时候写丑了. 从这道题中得到一个结论 dp方程要写的优美一点 不过写的过丑 优化都优化不了. ...
- 【洛谷比赛】[LnOI2019]长脖子鹿省选模拟赛 T1 题解
今天是[LnOI2019]长脖子鹿省选模拟赛的时间,小编表示考的不怎么样,改了半天也只会改第一题,那也先呈上题解吧. T1:P5248 [LnOI2019SP]快速多项式变换(FPT) 一看这题就很手 ...
- 6.28 NOI模拟赛 好题 状压dp 随机化
算是一道比较新颖的题目 尽管好像是两年前的省选模拟赛题目.. 对于20%的分数 可以进行爆搜,对于另外20%的数据 因为k很小所以考虑上状压dp. 观察最后答案是一个连通块 从而可以发现这个连通块必然 ...
- Divide two numbers,两数相除求商,不能用乘法,除法,取模运算
问题描述:求商,不能用乘法,除法,取模运算. 算法思路:不能用除法,那只能用减法,但是用减法,超时.可以用位移运算,每次除数左移,相当于2倍. public class DividTwoInteger ...
- @省选模拟赛03/16 - T3@ 超级树
目录 @description@ @solution@ @accepted code@ @details@ @description@ 一棵 k-超级树(k-SuperTree) 可按如下方法得到:取 ...
随机推荐
- Java面向对象—常见面试题
2. Java 面向对象 2.1. 类和对象 2.1.1. 面向对象和面向过程的区别 面向过程 :面向过程性能比面向对象高. 因为类调用时需要实例化,开销比较大,比较消耗资源,所以当性能是最重要的考量 ...
- BUUCTF-Misc-No.1
# BUUCTF-Misc # 签到 flag{buu_ctf} 金三胖 说实话直接看出来flag{he11ohongke} 二维码 直接binwalk扫一下,-e分离就出来一个带锁的zip爆破一下就 ...
- testNG jar包启动找不到org.testng.TestNG
主要是因为打包时依赖的jar包没有打入,网上有很多需要将对应的jar单独拷贝出来然后通过classpath引用启动,但是感觉这个就是个无底洞.拷贝了这么多个包最后还是说找不到ObjectId 启动命令 ...
- 数据分析04 /基于pandas的DateFrame进行股票分析、双均线策略制定
数据分析04 /基于pandas的DateFrame进行股票分析.双均线策略制定 目录 数据分析04 /基于pandas的DateFrame进行股票分析.双均线策略制定 需求1:对茅台股票分析 需求2 ...
- 一文读懂对抗生成学习(Generative Adversarial Nets)[GAN]
一文读懂对抗生成学习(Generative Adversarial Nets)[GAN] 0x00 推荐论文 https://arxiv.org/pdf/1406.2661.pdf 0x01什么是ga ...
- Linux 通过源代码安装和编译程序
Linux源代码安装在平常工作学习中经常用到,总结下步骤↓↓↓ 第一步:#mount /dev/cdrom/mnt (挂载一个软盘) 第二步:手动安装httpd-2.4.25.tar.gz 依赖关系包 ...
- 循序渐进VUE+Element 前端应用开发(18)--- 功能点管理及权限控制
在一个业务管理系统中,如果我们需要实现权限控制功能,我们需要定义好对应的权限功能点,然后在界面中对界面元素的功能点进行绑定,这样就可以在后台动态分配权限进行动态控制了,一般来说,权限功能点是针对角色进 ...
- Windows下配置ChromeDriver
1.查看自己chrome浏览器的版本. 浏览器地址栏输入以下地址 chrome://version 2.通过自己的版本下载相应的chromedriver.exe 下载地址:http://npm.tao ...
- [Qt插件]-02创建应用程序插件(插件化开发的一种思路)
本篇是学习Qt Creator快速入门,插件开发的笔记 分为两部分 创建插件 使用插件的应用程序(测试插件) 插件是被使用的应用程序加载使用的. 是使用插件的应用程序定义接口,插件按照接口来实 ...
- 像写Flutter一样开发Android原生应用
要问到Flutter和Android原生App,在开发是有何区别,编程方式是绕不开的话题.Flutter采用声明式编程,Android原生开发则采用命令式编程. 声明式编程 VS. 命令式编程 我们首 ...