TopCoder SRM 575 Div1 500 TheSwapsDivOne

53 篇文章 0 订阅
27 篇文章 0 订阅
本文介绍了一种使用动态规划(DP)方法解决涉及序列中元素位置变化概率问题的算法。通过定义状态f[i][0/1]来表示经过i次交换后,元素是否在原来位置上的概率,并给出详细的转移方程。最后,计算特定位置被子序列包含的概率,解决了问题。文章还分享了编程实现过程中的注意事项。
摘要由CSDN通过智能技术生成

每个数只有两种情况,要么在原来的位置上,要么不在。
于是我们用一个简单的dp求出两种情况的概率。
f [ i ] [ 0 / 1 ] f[i][0/1] f[i][0/1]:Swap了 i i i次后,0表示不在原来位置上,1表示在,的概率。

转移方程

  • f [ i ] [ 1 ] = f [ i − 1 ] [ 1 ] ∗ ( n − 2 ) / n + f [ i − 1 ] [ 0 ] ∗ 2 / n / ( n − 1 ) f[i][1]=f[i-1][1]*(n-2)/n+f[i-1][0]*2/n/(n-1) f[i][1]=f[i1][1](n2)/n+f[i1][0]2/n/(n1)
  • f [ i ] [ 0 ] = f [ i − 1 ] [ 1 ] ∗ 2 / n + f [ i − 1 ] [ 0 ] ∗ ( 1 − 2.0 / n / ( n − 1 ) ) f[i][0]=f[i-1][1]*2/n+f[i-1][0]*(1-2.0/n/(n-1)) f[i][0]=f[i1][1]2/n+f[i1][0](12.0/n/(n1))

剩下的就很水了吧。只要求出 i i i这个位置被子序列包含的概率就行了,这个就是 i ∗ ( n − i + 1 ) n ∗ ( n + 1 ) / 2 \frac{i*(n-i+1)}{n*(n+1)/2} n(n+1)/2i(ni+1)

一开始因为没开 l o n g   l o n g long\ long long long FST了(;′⌒`)

#include <bits/stdc++.h>
#define fr(i,x,y) for(int i=x;i<=y;i++)
#define ll long long
using namespace std;
const int N=1000005;
double f[N][2];
ll n;
ll a[2505];

template<class T> void checkmin(T &a,const T &b) { if (b<a) a=b; } 
template<class T> void checkmax(T &a,const T &b) { if (b>a) a=b; }

class TheSwapsDivOne {
public:
    double find( vector <string> sequence, int k ) ;
};
double TheSwapsDivOne::find(vector <string> ss, int k) {
	string s;
	for(int i=0;i<ss.size();i++) s+=ss[i];
    f[0][1]=1;n=s.size();
    //cout<<n<<endl;
    fr(i,1,k){
    	f[i][1]=f[i-1][1]*(n-2)/n+f[i-1][0]*2/n/(n-1);
    	f[i][0]=f[i-1][1]*2/n+f[i-1][0]*(1-2.0/n/(n-1));
    }
    ll sum=0,w;
    fr(i,1,n) a[i]=s[i-1]-'0',sum+=a[i];
    ll z=n*(n+1)/2;
    double ans=0;
    fr(i,1,n){
    	w=i*(n-i+1);
    	ans+=a[i]*f[k][1]*w;
    	ans+=w*(sum-a[i])*f[k][0]/(n-1);
    }
    ans/=z;
    return ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值