• 换教室(期望+DP)


    换教室(期望+DP)

    (dp(i,j,1/0))表示第(i)节课,申请了(j)次调换,这节课(1/0)调换。

    换教室

    转移的时候考虑:

    • 上次没申请

      • 这次也没申请

        加上(dis(fr[0],to[0]))

      • 这次申请

        加上(p imes dis(fr[0],to[1])+(1-p) imes dis(fr[0],to[0]))

    • 上次申请

      • 这次申请

        加上(p'p imes dis(fr[1],to[1])+p'(1-p) imes dis(fr[1],to[0])+(1-p')p imes dis(fr[0],to[1])+(1-p')(1-p) imes dis(fr[0],to[0]))

      • 这次不申请

        加上(p' imes dis(fr[1],to[0])+(1-p') imes dis(fr[0],to[0]))

    直接转移即可。

    Q:为什么之前(dp)的值不要乘概率?

    A:这是因为前面的期望和后面无关,前面的概率已经确定了。所以不需要乘上本次的概率。

    Q:为什么要考虑这么多(1-p)的情况?

    A:这是因为我们设计的dp是"是否申请",是否申请和是否换教室是不同的,他们之间有概率的关系。

    
    //@winlere
    #include<bits/stdc++.h>
    #define int long long 
    using namespace std;  typedef long long ll;
    template < class ccf > inline ccf qr(ccf ret){      ret=0;
          register char c=getchar();
          while(not isdigit(c)) c=getchar();
          while(isdigit(c)) ret=ret*10+c-48,c=getchar();
          return ret;
    }inline int qr(){return qr(1);}
    const int maxn=25;
    const ll mod=1e9+7;
    inline ll Pow(ll base,ll p){
          base%=mod;
          register ll ret=1;
          for(;p;p>>=1,base=base*base%mod)
    	    if(p&1) ret=ret*base%mod;
          return ret;
    }
    ll data[maxn],s,ans,inv[maxn]={1},jie[maxn]={1};
    int n;
    
    inline ll C(const ll&n,const ll&m){
          if(n<m||m<0||n<0)return 0;
          if(n==m)return 1;
          register ll ret=inv[m];
          for(register ll t=n;t>=n-m+1ll;--t)
    	    ret=t%mod*ret%mod;
          return ret;
    }
    #undef int
    int main(){
    #define int long long 
    #ifndef ONLINE_JUDGE
          freopen("in.in","r",stdin);
          //freopen("out.out","w",stdout);
    #endif
          for(register int t=1;t<maxn;++t)
    	    inv[t]=inv[t-1]*Pow(t,mod-2ll)%mod;
          n=qr();s=qr(1ll);ans=C(s+n-1ll,n-1ll);
          for(register int t=1;t<=n;++t)
    	    data[t]=qr(1ll);
          for(register int t=1,edd=1<<n,cnt=0;t<edd;++t){
    	    ll f=cnt=0,delt;
    	    for(register int i=1;i<=n;++i)
    		  if(t<<1>>i&1)
    			f+=data[i]+1ll,++cnt;
    	    delt=C(s-f+n-1ll,n-1ll);
    	    if(cnt&1) ans=(ans-delt)%mod,ans=ans<0?ans+mod:ans;
    	    else ans=(ans+delt)%mod;
          }
          cout<<ans<<endl;
          return 0;
    }
    
  • 相关阅读:
    shell编程
    redis不重启,切换RDB备份到AOF备份
    java中接口和抽象类的区别
    java中的泛型
    java中有关初始化的问题
    java中的多态
    java中的Iterator和ListIterator的区别
    Collection集合的三种初始化方法
    java正则表达式appendReplacement和appendTail方法
    java中main函数的String[] args
  • 原文地址:https://www.cnblogs.com/winlere/p/10828220.html
Copyright © 2020-2023  润新知