首页 > 其他分享 >[P4317 花神的数论题]题解

[P4317 花神的数论题]题解

时间:2023-04-15 13:35:38浏览次数:44  
标签:int 题解 sum 花神 num limit P4317 id dp

P4317 花神的数论题【数位DP】

题目描述

最开始其实没有什么想法
第一次遇见数位dp求相乘的题
想就按照常规做法来做,但不知道如何去处理*
于是写了一个错误的代码

//当前枚举到第id位,前面的1的个数为sum,是否达到上限limit
ll dfs(int id,int sum,int limit){
  //1.出口
  if(id==0) return 1ll*sum;
  if(dp[id][sum][limit]!=-1) return dp[id][sum][limit];
  //2.能做的事情 
  int bound=limit?a[id]:1;
  ll res=1;
  for(int i=(id==1?1:0);i<=bound;i++)
    res=1ll*res*dfs(id-1,sum+(i==1),limit&&i==bound)%mod;
  return dp[id][sum][limit]=res%mod;
} 

ll solve(ll x){
  len=0;
  memset(dp,-1,sizeof(dp));
  while(x){
  	a[++len]=x%2;
  	x/=2;
  }
  return dfs(len,0,1);
}

很明显我知道是错的
但又不太清楚是哪里错了
应该是在乘法的记忆化上面出了一些问题
提交上去也只有10分
……
[看了看题解]
……
我们不妨换一个角度来思考
它要求每一个数的\(sum\)乘积
由于\(n \leq 10^{15}\)
所以其实\(sum\)是有限的
也就是\(0 \to 50\)中的数
所以我们可以把每一个\(sum\)的个数都求出来再用快速幂乘起来
这样就是一个很典型的数位dp了
但对于每一个不同的\(sum\)
我们都要用一次\(dfs\)去求,不然是无法用上记忆化
会导致\(TLE\)

//当前枚举到第id位,前面1的数量为sum,正在统计num的个数,是否达到上限limit
//统计cnt[sum],sum出现的次数 
ll dfs(int id,int sum,int num,int limit){
  //1.出口
  if(id==0) return sum==num;
  if(dp[id][sum][num][limit]!=-1) return dp[id][sum][num][limit];
  //2.能做的事情 
  int bound=limit?a[id]:1;
  ll res=0;
  for(int i=0;i<=bound;i++)
    res+=dfs(id-1,sum+(i==1),num,limit&&i==bound); 
  return dp[id][sum][num][limit]=res;
}

ll quickpow(ll a,ll b){
  ll res=1;
  while(b){
    if(b&1) res=res*a%mod;
    a=a*a%mod;
    b/=2;
  }
  return res%mod;
}

int main(){
  /*2023.4.15 hewanying P4317 花神的数论题 数位DP*/ 
  scanf("%lld",&n);
  memset(dp,-1,sizeof(dp));
  len=0;
  while(n){
  	a[++len]=n%2;
  	n/=2;
  }
  ans=1ll;
  for(int i=1;i<=len;i++) 
    ans=ans*quickpow(1ll*i,dfs(len,0,i,1))%mod;
  printf("%lld\n",ans);
  return 0;
}

总结

对于这种要转个弯的数位dp题,我们的目的还是要把乘积转化成加法
考虑答案的构成,把相同的sum放在一块
这样就可以把题目中的\(\Pi\)转化成\(\Sigma\)
便可以用数位dp解决了

标签:int,题解,sum,花神,num,limit,P4317,id,dp
From: https://www.cnblogs.com/hewanying0622/p/17320946.html

相关文章

  • CF1592F2 题解
    题意传送门给定一个\(n\)行\(m\)列的目标矩阵,矩阵元素只有W或B,并且你有一个初始矩阵,元素全为W。现在你可以矩阵实施以下操作:使用一块钱,选定一个包含\((1,1)\)的子矩阵,把矩阵中的元素全部反转(W变B,B变W)。使用三块钱,选定一个包含\((n,1)\)的子矩阵,把矩阵......
  • Luogu_P1613 跑路 题解
    发现和最短路差不多,不过不能朴素的跑最短路。考虑对于每两个相隔\(2\)的整数次幂的点建边,在这个新图上跑最短路就是答案。设\(f_{i,j,k}\)表示从点\(i\)跳\(2^k\)步能否到点\(j\),转移方程就是一个普通的倍增。如果点\(i\)和点\(j\)可以一步到达,那么就在新图上建一条......
  • ABC249F 题解
    前言题目传送门!更好的阅读体验?很好玩的贪心。思路如果第\(i\)次操作为覆盖操作,那么\(1\simi-1\)次操作都是无效的,原因显然。这启示我们从后往前扫(前面的会被忽略,后面的不会啊!)。在此基础上,就是分类讨论一下(假设当前的最大答案为\(sum\)):当前操作是覆盖操作:如果不......
  • 【题解】Tree MST
    题面给定一棵\(n\)个节点的树,现有有一张完全图,两点\(x,y\)之间的边长为\(w_x+w_y+dis_{x,y}\),其中\(dis\)表示树上两点的距离。求完全图的最小生成树。\(n\leq2\times10^5\)。题解???神秘借鉴支配对的思想,点分治后将树中点权替换为\(dep_i+w_i\),选择点权最小的一个......
  • [ABC296Ex] Unite 题解
    考虑状压dp。设\(f_{i,j,s}\)表示当前正在决策坐标为\((i,j)\)的格子,且列状态为\(s\)。其中列状态维护了当前轮廓线上的连通块,我们可以使用最小表示法来简单维护。(为什么不用广义括号序列?因为其涉及到\(5\)个可选值,由于\(m\le7\),所以这两个都需要用到八进制,而最小表示......
  • [Educational Codeforces Round 118 (Rated for Div. 2)]题解
    A题意:给定两个数,每一个数有两个属性,第一个属性是p1,第二个属性是p2.表示这个数有p2个后缀0.这个数本身等于p1后面加p2个0.问给你两个这种数,判断大小。思路:赛场上想到的:如果最终的长度不一样,可以直接根据长度判断。如果相等,就把后缀0加上直接比较大小就可以(比较字典序的大小),但......
  • 2012-2013 ACM-ICPC, NEERC, Moscow Subregional Contest题解
    题目链接:2012-2013ACM-ICPC,NEERC,MoscowSubregionalContestC.Cinderella(贪心)思路答案为大于平均值的数的数量代码#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;intmain(){ios::sync_with_stdio(false);cin.tie(nullptr);......
  • CF1473D 题解
    题目传送门题目分析线段树、前缀和、\(\text{ST}\)表题解都有了,我补一发猫树题解吧。由于每次操作只能将大小改变成跟原来差\(1\),所以只需要知道这段操作中的最大值和最小值,最后所求的答案的范围就被卡住了。对于每一次操作,我们把操作序列拦腰斩断,那么分别求两边的范围,最后减......
  • CF1758D 题解
    前言题目传送门!更好的阅读体验?用一种非常麻烦的做法把自己写自闭了,和题解区不一样,但是方法困难很多。思路代码属于混乱邪恶了,凑合着看看。#include<iostream>#include<cstdio>#include<cmath>usingnamespacestd;intn,ans[300005];longlongcalc(){ longlo......
  • ubuntu 20.04 基于docker快速搭建中文 的一些问题解决 Utilization of discoverer pro
    1.Utilizationofdiscovererprocessesover75%解决办法问题状态如下zabbixserver在开启Discovery功能后,zabbixweb页面报警提示:“Zabbixserver:Ulitizationofdiscovererprocessesover75%”。原因:每个discovery任务占用一个discovery进程,但是zabbixserver默认只配置了一......