zoukankan      html  css  js  c++  java
  • [CSP校内集训]kat(期望DP)

    题意

    一本有n道题的练习册,katarina大佬每天都会做k道题。
    第一天做第1k题,第二天做第2k+1题……第n-k+1天做第n−k+1~n道题。
    每道题有它的难度值,假设今天katarina大佬做的题目中最大难度为t,那么今天katarina大佬的劳累度就是(w_t),做完这本书的劳累值就是每天的劳累值之和。
    题目的难度在1~m随机,求做完整本书的期望劳累值

    (n,m leq 500 , mod = 10^9+7)

    思路

    由于前面两道题都有点迷所以还以为这道题也是道神题

    性质:求每种排列的贡献和 等价于 一个滑动窗口的贡献( imes) ((n-k+1))

    性感)证明

    根据题意有:$$ans = sum_{i=1}{mn}{ (frac{1}{m^n} imes (a_1^i + a_2^i + ....... + a_{n-k+1}^i)) }$$其中(a_j^i)表示在第(i)种排列下第(j)个滑动窗口的贡献

    显然这个东西可以用乘法分配律按照(j)分开:$$ans = sum_{j=1}{n-k+1}{(frac{1}{mn} imes (a_j^1 + a_j^2 + ....... + a_j{mn}))}$$

    对于一个滑动窗口,在它范围外的其他格子不管怎么变都不会影响它的贡献,所以这样的(a)是相同的,每种贡献有(m^{n-k})

    把相同贡献的变成一个,最后变成:$$ans = sum_{j=1}^{n-k+1}{ (frac{1}{m^k} imes (a_j^1 + a_j^2 + ........ + a_j{m{n-k}}))) }$$

    发现此时答案为每个滑动窗口单独的贡献加起来,而每个滑动窗口的贡献又相同,所以就等于单个贡献( imes) ((n-k+1))

    对单个滑窗期望DP即可,这个复杂度可以是(O(mlogn))或者(O(nm)),比较基础就不写了(不能理解题解(O(n^2m))的睿智做法

    本题难点不在期望DP而在简化问题(当然像题解一样直接莽就另当别论了),其实(m)可以开到(10^5)

    Code

    #include<bits/stdc++.h>
    #define N 505
    #define Min(x,y) ((x)<(y)?(x):(y))
    #define Max(x,y) ((x)>(y)?(x):(y))
    using namespace std;
    typedef long long ll;
    const ll mod = 1000000007;
    int n,m,k;
    ll a[N],f[N][N],sum[N][N];
    
    template <class T>
    void read(T &x)
    {
    	char c; int sign=1;
    	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    	while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
    }
    ll quickpow(ll a,ll b)
    {
    	ll ret=1;
    	while(b)
    	{
    		if(b&1) ret=ret*a%mod;
    		a=a*a%mod;
    		b>>=1;
    	}
    	return ret;
    }
    
    int main()
    {
    	freopen("kat.in","r",stdin);
    	freopen("kat.out","w",stdout);
    	read(n);read(m);read(k);
    	for(int i=1;i<=m;++i) read(a[i]);
    	for(int i=1;i<=m;++i) f[1][i]=quickpow(m,mod-2),sum[1][i]=(sum[1][i-1]+f[1][i])%mod;
    	for(int i=2;i<=k;++i)
    	{
    		for(int j=1;j<=m;++j)
    		{
    			f[i][j]=(sum[i-1][j-1]+f[i-1][j]*j%mod)*quickpow(m,mod-2)%mod;
    			sum[i][j]=(sum[i][j-1]+f[i][j])%mod;
    		}
    	}
    	ll ans=0;
    	for(int i=1;i<=m;++i) ans=(ans + f[k][i]*a[i]%mod)%mod;
    	cout<<(ans*(n-k+1)%mod+mod)%mod<<endl;
    	return 0;
    }
    
  • 相关阅读:
    Asp.Net选择TreeView前面的复选框引起回发
    Asp.Net自动发送邮件代码
    Asp.Net类型转换类(通用类)
    Eclipse 快捷键
    结对项目开发之电梯调度问题
    输出文章中几个最高频率单词和次数
    求整数数组中和最大的子数组的和
    Android定位功能(二)
    分布式拒绝服务攻击(DDoS)原理及防范
    定义Profile用户文件详解
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11762707.html
Copyright © 2011-2022 走看看