LGP5075【JSOI2012】分零食

  • 题解:

    • 令$F$为欢乐度$f(x) = Ox^2 + Sx + U$的生成函数,常数项为$0$;
    • 令$G(x) = \sum_{i=0}^{A} F^i (x) $
    • $ans = [x^M]G;$
    • 模数比较麻烦所以我用的分治求:
    • 如果现在要求$0$到$n-1$的$G_{n} = \sum_{i=0}^{n-1}F^{i}$和$F_{n} = F^{n} $,假设n为偶数;
    • 那么分治求出关于$n/2$的答案$G_{\frac{n}{2}}$和$F_{\frac{n}{2}}$
    • $$G_{n} = (F_{\frac{n}{2}}+1)G_{\frac{n}{2}}  , F_{n} = F_{\frac{n}{2}}^2$$
    • 如果$n$是奇数先算用上述操作算$n-1$,再把$F_{n-1}$补加给$G_{n-1}$得到$G_{n}$,最后$F_{n-1}$另外乘一次得到$F_{n}$;
    • 和快速幂的思想差不多;
    •  1 #include<bits/stdc++.h>
       2 #define ld double
       3 using namespace std;
       4 const int N=40010;
       5 const ld pi=acos(-1);
       6 int M,P,A,O,S,U,len,L,rev[N];
       7 struct C{
       8     ld x,y;
       9     C(ld _x=0,ld _y=0):x(_x),y(_y){};
      10     C operator +(const C&A)const{return C(x+A.x,y+A.y);}
      11     C operator -(const C&A)const{return C(x-A.x,y-A.y);}
      12     C operator *(const C&A)const{return C(x*A.x-y*A.y,x*A.y+y*A.x);}
      13     C operator /(const ld&A)const{return C(x/A,y/A);}
      14 }f[N],g[N],t[N];
      15 int cal(int x){return (O*x*x+S*x+U)%P;}
      16 void fft(C*a,int f){
      17     for(int i=0;i<len;++i)if(i<rev[i])swap(a[i],a[rev[i]]);
      18     for(int i=1;i<len;i<<=1){
      19         C wn=C(cos(pi/i),f*sin(pi/i));
      20         for(int j=0;j<len;j+=i<<1){
      21             C w=C(1,0);
      22             for(int k=0;k<i;++k,w=w*wn){
      23                 C x=a[j+k],y=w*a[j+k+i];
      24                 a[j+k]=x+y,a[j+k+i]=x-y;
      25             }
      26         }
      27     }
      28     if(!~f)for(int i=0;i<len;++i){
      29         a[i]=a[i]/len;
      30         a[i].x=int(a[i].x+0.1)%P;
      31         a[i].y=0;
      32     }
      33 }
      34 void solve(int A){
      35     if(A==1){g[0].x=1;return;}
      36     solve(A>>1);
      37     fft(f,1);fft(g,1);
      38     for(int j=0;j<len;++j)g[j]=g[j]*(f[j]+C(1,0)),f[j]=f[j]*f[j];
      39     fft(f,-1);fft(g,-1);
      40     for(int j=M+1;j<len;++j)f[j].x=g[j].x=0; 
      41     if(A&1){
      42         for(int j=0;j<=M;++j)g[j].x=(int)(g[j].x+f[j].x+0.1)%P; 
      43         fft(f,1);for(int j=0;j<len;++j)f[j]=f[j]*t[j];
      44         fft(f,-1);for(int j=M+1;j<len;++j)f[j].x=0;
      45     }
      46 }
      47 int main(){
      48 //    freopen("P5075.in","r",stdin);
      49 //    freopen("P5075.out","w",stdout);
      50     scanf("%d%d%d%d%d%d",&M,&P,&A,&O,&S,&U);
      51     for(int i=1;i<=M;++i)t[i].x=f[i].x=cal(i%P);
      52     for(len=1;len<=M<<1;len<<=1,L++);
      53     for(int i=0;i<len;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
      54     fft(t,1);solve(min(A,M)+1);
      55     printf("%d\n",(int)(g[M].x+0.1)%P);
      56     return 0;
      57 }
      View Code

       

转载于:https://www.cnblogs.com/Paul-Guderian/p/10433414.html

根据引用[1],dp[u][j]表示在u子树中选取恰好j个人时能获得的最大价值。而根据引用,该问题的时间复杂度为O(log2​104×nm)。 对于洛谷P2143 [JSOI2010] 巨额奖金问题,我们可以使用动态规划来解决。具体步骤如下: 1. 首先,我们需要构建一棵树来表示员工之间的关系。树的根节点表示公司的总经理,其他节点表示员工。每个节点都有一个权值,表示该员工的奖金金额。 2. 接下来,我们可以使用动态规划来计算每个节点的dp值。对于每个节点u,我们可以考虑两种情况: - 如果选择节点u,则dp[u][j] = dp[v][j-1] + value[u],其中v是u的子节点,value[u]表示节点u的奖金金额。 - 如果不选择节点u,则dp[u][j] = max(dp[v][j]),其中v是u的子节点。 3. 最后,我们可以通过遍历树的所有节点,计算出dp[u][j]的最大值,即为所求的巨额奖金。 下面是一个示例代码,演示了如何使用动态规划来解决洛谷P2143 [JSOI2010] 巨额奖金问题: ```python # 构建树的数据结构 class Node: def __init__(self, value): self.value = value self.children = [] # 动态规划求解最大奖金 def max_bonus(root, j): dp = [[0] * (j+1) for _ in range(len(root)+1)] def dfs(node): if not node: return for child in node.children: dfs(child) for k in range(j, 0, -1): dp[node.value][k] = max(dp[node.value][k], dp[node.value][k-1] + node.value) for child in node.children: for k in range(j, 0, -1): for l in range(k-1, -1, -1): dp[node.value][k] = max(dp[node.value][k], dp[node.value][k-l-1] + dp[child.value][l]) dfs(root) return dp[root.value][j] # 构建树 root = Node(1) root.children.append(Node(2)) root.children.append(Node(3)) root.children[0].children.append(Node(4)) root.children[0].children.append(Node(5)) root.children[1].children.append(Node(6)) # 求解最大奖金 j = 3 max_bonus_value = max_bonus(root, j) print("最大奖金为:", max_bonus_value) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值