• Codeforces Round 896 (Div. 1) C. Travel Plan(树形dp+组合数学)


    题目

    有一棵n(1<=n<=1e18)个点的树,

    点i连着2*i和2*i+1两个点,构成一棵完全二叉树

    对于每个点i,记其值为a[i],a[i]可以取[1,m](1<=m<=1e5)的整数

    记i到j的简单路径上的最大值为s[i][j],

    则一棵权值确定的树对答案的贡献是\sum_{i=1}^{n}\sum_{j=i+1}^{n}s[i][j]

    现在求所有可能情况下的树的贡献之和,答案对998244353取模

    实际t<=200组样例,但保证summ不超过1e5

    思路来源

    羊村群小羊

    题解

    大致的思路就是把每个长度的路径都统计算出来,然后再算贡献

    而n个点的树总是可以拆成左子树和右子树继续递归下去的,有子结构的概念

    所以可以按子树大小做记忆化,每棵子树暴力维护所有长度的路径进行合并

    由于路径长度最长2*logn,这里固定开了128长度的vector,只对这些做合并

    dp[i][2]表示当前节点u的子树长度为i的路径的条数

    其中dp[i][0]表示两端都位于子树内部的路径,dp[i][1]表示有一端位于根节点的路径

    求出路径方案数后求贡献,最大值为i的方案数,首先特判i=1,

    然后稍作容斥,方案数等于m个值从[1,i]任取减去m个值从[1,i-1]任取

    长为i的路径的方案数*剩下n-i个点任取的方案数*最大值为j的方案数*最大值j,

    就是当路径长度为i,而最大值为j时,(i,j)对答案的贡献,统计所有贡献累加即可

    心得

    int k = std::__lg(n + 1);
    ll ls=((1LL << (k - 1)) - 1) + std::min(1LL << (k - 1), n - (1LL << k) + 1);
    ll rs=n-1-ls;

    求左子树大小这里,抄了一下jiangly的代码,但后来想了想也很好理解

    对于倒数第二层往上,是左右子树平分的

    而对于最后一层,左子树能拿到的大小,为min(剩下的点数,最后一层的一半)

    代码

    1. #include
    2. using namespace std;
    3. #define rep(i,a,b) for(int i=(a);i<=(b);++i)
    4. #define per(i,a,b) for(int i=(a);i>=(b);--i)
    5. typedef long long ll;
    6. typedef double db;
    7. typedef array<int,2> P;
    8. #define fi first
    9. #define se second
    10. #define pb push_back
    11. #define dbg(x) cerr<<(#x)<<":"<" ";
    12. #define dbg2(x) cerr<<(#x)<<":"<
    13. #define SZ(a) (int)(a.size())
    14. #define sci(a) scanf("%d",&(a))
    15. #define pt(a) printf("%d",a);
    16. #define pte(a) printf("%d\n",a)
    17. #define ptlle(a) printf("%lld\n",a)
    18. #define debug(...) fprintf(stderr, __VA_ARGS__)
    19. typedef unsigned ui;
    20. //typedef __uint128_t L;
    21. typedef unsigned long long L;
    22. typedef unsigned long long ull;
    23. const int N=1e5+10,M=128,mod=998244353;
    24. int t,m,pw[N][M];
    25. ll n;
    26. map>mp;//dp[i][2]表示是否开口的方案数
    27. void add(int &x,int y){
    28. x=(x+y)%mod;
    29. }
    30. vector

      dfs(ll n){

    31. if(n==0)return vector

      (1,{0,0});

    32. if(n==1)return vector

      (1,{0,1});

    33. if(mp.count(n))return mp[n];
    34. int k = std::__lg(n + 1);
    35. ll ls=((1LL << (k - 1)) - 1) + std::min(1LL << (k - 1), n - (1LL << k) + 1);
    36. ll rs=n-1-ls;
    37. vector

      l=dfs(ls),r=dfs(rs);

    38. int sl=SZ(l),sr=SZ(r);
    39. //printf("n:%lld lsz:%d rsz:%d\n",n,sl,sr);
    40. vector

      dp(128,{0,0});

    41. rep(i,0,sl-1){
    42. rep(j,0,sr-1){
    43. if(!l[i][1] || !r[j][1])continue;
    44. add(dp[i+j+2][0],1ll*l[i][1]*r[j][1]%mod);
    45. }
    46. }
    47. rep(i,0,sl-1){
    48. add(dp[i][0],l[i][0]);
    49. add(dp[i][0],l[i][1]);
    50. add(dp[i+1][1],l[i][1]);
    51. }
    52. rep(i,0,sr-1){
    53. add(dp[i][0],r[i][0]);
    54. add(dp[i][0],r[i][1]);
    55. add(dp[i+1][1],r[i][1]);
    56. }
    57. add(dp[0][1],1);
    58. return mp[n]=dp;
    59. }
    60. int modpow(int x,ll n,int mod){
    61. if(!n)return 1;
    62. int res=1;
    63. for(;n;n>>=1,x=1ll*x*x%mod){
    64. if(n&1)res=1ll*res*x%mod;
    65. }
    66. return res;
    67. }
    68. int cal(int sz,int v){
    69. if(v==1)return 1;
    70. return (pw[v][sz]-pw[v-1][sz]+mod)%mod;
    71. }
    72. int sol(){
    73. vector

      dp=dfs(n);

    74. int sz=SZ(dp),res=0;
    75. rep(j,0,sz-1){
    76. int cnt=(dp[j][0]+dp[j][1])%mod,len=j+1;
    77. if(len>n)break;
    78. int oth=modpow(m,n-len,mod)%mod;
    79. rep(i,1,m){
    80. add(res,1ll*cnt*cal(len,i)%mod*i%mod*oth%mod);
    81. }
    82. }
    83. return res;
    84. }
    85. int main(){
    86. rep(i,1,N-1){
    87. pw[i][0]=1;
    88. rep(j,1,M-1){
    89. pw[i][j]=1ll*pw[i][j-1]*i%mod;
    90. }
    91. }
    92. sci(t);
    93. while(t--){
    94. scanf("%lld%d",&n,&m);
    95. printf("%d\n",sol());
    96. }
    97. return 0;
    98. }

  • 相关阅读:
    Android Studio实现记单词App,背完四六级一次过~
    在一台笔记本电脑上试用Ubuntu22.04
    跨域问题WebMvcConfigurer
    Chrome Dev Tools
    国科大-计算机算法设计与分析-卜东波作业3
    Python接口自动化搭建过程,含request请求封装
    习题1. 31
    java中volatile解决可见性和有序性问题
    解决idea maven 不使用本地库jar包问题
    MQTT协议基本流程、原理
  • 原文地址:https://blog.csdn.net/Code92007/article/details/132893371