#期望dp#洛谷 3750 分手是祝愿

本文介绍了一种使用动态规划(DP)算法解决特定灯谜题的方法。通过逆序枚举亮着的灯,确定必须按键的数量,并设置状态dp[i]来表示有i个正确选择并选择正确的期望操作次数。文章提供了详细的DP方程和C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接


分析

首先判断必须得按的键的个数,这个倒序枚举亮着的灯,然后设 d p [ i ] dp[i] dp[i]表示有 i i i个正确选择并选择正确的期望操作次数,那么 d p [ i ] = i n + n − i n ( d p [ i ] + d p [ i + 1 ] + 1 ) + 1 , d p [ n + 1 ] = 0 dp[i]=\frac{i}{n}+\frac{n-i}{n}(dp[i]+dp[i+1]+1)+1,dp[n+1]=0 dp[i]=ni+nni(dp[i]+dp[i+1]+1)+1,dp[n+1]=0,若必须得按的键在 k k k以内就不需要随机了,否则答案就是 k + ∑ i = k + 1 c n t d p [ i ] k+\sum_{i=k+1}^{cnt}dp[i] k+i=k+1cntdp[i]


代码

#include <cstdio>
#include <cctype>
#include <cmath>
#define rr register
using namespace std;
typedef long long ll;
const int mod=100003;
bool a[mod]; int n,k,cnt;
ll dp[mod],inv[mod];
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
signed main(){
    n=iut(); k=iut();
    for (rr int i=1;i<=n;++i) a[i]=iut();
    for (rr int i=n;i;--i)
    if (a[i]){
        ++cnt; rr int t=sqrt(i);
        for (rr int j=1;j<=t;++j)
        if (i%j==0){
            a[j]^=1;
            if (j*j!=i) a[i/j]^=1; 
        }
    }
    dp[n+1]=0; inv[1]=1;
    for (rr int i=2;i<=n;++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    for (rr int i=n;i;--i)
        dp[i]=((n-i)*dp[i+1]+n)*inv[i]%mod;
    rr ll ans=cnt;
    if (cnt>k){
        ans=k;
        for (rr int i=cnt;i>k;--i) ans=(ans+dp[i])%mod;
    }
    for (rr int i=1;i<=n;++i) ans=ans*i%mod;
    return !printf("%lld",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值