ShinriiTin's Blog - 博主是sb

Swap

题意:

给出一个n*m(n<=103,m<=103)的黑白棋棋盘.

棋盘上有t(t<=105)个位置坏掉了。

除了坏掉的位置之外,每个位置上有且只有1颗棋子,且初始时白面向上。

你可以进行k(k<=109)次操作。

每次操作选择两颗棋子,将以它们为对角线的矩形内的所有棋子状态取反(不一定是主对角线).

问k次操作后,白面向上的棋子个数的期望值是多少。

 

分析:

由于期望具有线性性,我们可以分别计算每颗棋子的期望最后再求和。

假设某颗棋子在1次操作中被翻转的概率为p。

那么容易推出它k次操作后状态不变的概率为(1+(1-2*p)k)/2.

现在问题就在于如何快速求出p.

由容斥得(x,y)被翻转的情况有:

|([1,x]×[1,y],[x,y]×[n,m])|+|([x,n]×[1,y],[1,x]×[y,m])|-|([x,x]×[1,y],[x,x]×[y,m])|-|([1,x]×[y,y],[x,n]×[y,y])|+1

用前缀和优化就好了。

 

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define g() getchar()
template<class Q>void Scan(Q&x){
	char c;while(c=g(),c<48||c>57);
	for(x=0;c>47&&c<58;c=g())x=10*x+c-48;
}

#define rep(i,a,b) for(int i=a;i<b;++i)

const int MAXN=1005;

int n,m,k,t;

bool a[MAXN][MAXN];

int sum[MAXN][MAXN];

inline int Sum(int x1,int y1,int x2,int y2){
	int res=sum[x2][y2]-sum[x2][y1-1];
	return res-(sum[x1-1][y2]-sum[x1-1][y1-1]);
}

inline void Init(){
	Scan(n),Scan(m),Scan(k),Scan(t);
	rep(i,1,n+1)rep(j,1,m+1)sum[i][j]=a[i][j]=1;
	rep(i,1,t+1){
		int x,y;
		Scan(x),Scan(y);
		sum[x][y]=a[x][y]=0;
	}
	rep(i,1,n+1)rep(j,1,m+1)sum[i][j]+=sum[i][j-1];
	rep(i,1,n+1)rep(j,1,m+1)sum[i][j]+=sum[i-1][j];
}

typedef long double ld;
typedef long long ll;

inline ld qpow(ld x,int k){
	ld ans=1;
	for(;k;x=x*x,k>>=1)
		if(k&1)ans=ans*x;
	return ans;
}

ld ans;

inline void Solve(){
	ll q=1ll*sum[n][m]*sum[n][m];
	rep(i,1,n+1)rep(j,1,m+1){
		if(!a[i][j])continue;
		ll p=1ll*Sum(1,1,i,j)*Sum(i,j,n,m)+1ll*Sum(1,j,i,m)*Sum(i,1,n,j);
		p-=1ll*Sum(i,1,i,j)*Sum(i,j,i,m)+1ll*Sum(1,j,i,j)*Sum(i,j,n,j);
		p=p<<1|1;
		ld pr=(ld)p/q;
		ans+=(qpow(1.-pr*2.,k)+1.)/2.;
	}
	printf("%.20f\n",(double)ans);
}

int main(){
	freopen("swap.in","r",stdin);
	freopen("swap.out","w",stdout);
	Init(); Solve(); return 0;
}
 

codeforces round265 div1 D World of Darkraft - 2

详见zhj的15年集训队论文

Portal

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define rep(i,a,b) for(int i=a;i<b;++i)
typedef long double ld; 

const int MAXN=1000; 

int n,k,cur;

ld dp[2][MAXN];

int main(){
	scanf("%d%d",&n,&k);
	for(int i=n;i;--i){
		cur^=1;
		int B=701;
		rep(j,1,B){
			dp[cur][j]=(dp[cur^1][j]+(1.+j)/2)*j;
			dp[cur][j]+=(dp[cur^1][j+1]+j);
			dp[cur][j]/=j+1;
			dp[cur][j]+=dp[cur^1][j]*(k-1);
			dp[cur][j]/=k;
		}
	}
	ld ans=dp[cur][1]*k;
	printf("%.20f\n",(double)ans);
	return 0;
}