1. 程式人生 > >SCU 4519 來個簽到吧 (exgcd推廣+概率dp)

SCU 4519 來個簽到吧 (exgcd推廣+概率dp)

題目傳送門:http://acm.scu.edu.cn/soj/problem.action?id=4519
這題開頭給你一些球,然後把任意球的編號之差|xy|的求加入進去,然後加滿球之後,問你把所有球都取出來過一遍的期望是多少
前面加球,任意兩個球x,y,經過很多操作之後可以得到間隔是gcd(x,y)的所有球,然後這題開頭有若干個球,所以最後得到的間隔是所有球的gcd,然後如果有球是0,需要特判個數加1,然後有m個球了,就是概率dp的遞推了,考慮dp[i]為已經有i個球被取過了的期望

dp[i]=1+im×dp[i]+mim×dp[i+1]經過化簡得到dp[i]=dp[i+1]+mmi要記住概率dp推期望的時候,一定是倒著dp的,為什麼呢,我也不知道,最後問操作次數,需要加上前面的加球次數,這是個trick
#include <map>
#include <set> #include <stack> #include <queue> #include <cmath> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000") using namespace std; #define MAX 100005 #define MAXN 1000005 #define maxnode 10 #define sigma_size 2 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lrt rt<<1 #define rrt rt<<1|1
#define middle int m=(r+l)>>1 #define LL long long #define ull unsigned long long #define mem(x,v) memset(x,v,sizeof(x)) #define lowbit(x) (x&-x) #define pii pair<int,int> #define bits(a) __builtin_popcount(a) #define mk make_pair #define limit 10000 //const int prime = 999983; const int INF = 0x3f3f3f3f; const LL INFF = 0x3f3f; const double pi = acos(-1.0); const double inf = 1e18; const double eps = 1e-9; const LL mod = 1e9+7; const ull mxx = 1333331; /*****************************************************/ inline void RI(int &x) { char c; while((c=getchar())<'0' || c>'9'); x=c-'0'; while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; } /*****************************************************/ int gcd(int a,int b){ if(!b) return a; return gcd(b,a%b); } double dp[MAX]; int main(){ //freopen("in.txt","r",stdin); int t; cin>>t; while(t--){ int n; cin>>n; int tmp,maxn=0; int flag=0; for(int i=0;i<n;i++){ int b; scanf("%d",&b); if(i==0) tmp=b; else tmp=gcd(tmp,b); maxn=max(maxn,b); if(b==0) flag=1; } int num=maxn/tmp+flag; int add=num-n; dp[num]=0; //cout<<num<<endl; for(int i=num-1;i>=0;i--){ dp[i]=dp[i+1]+num*1.0/(num-i); } int ans=dp[0]+add; cout<<ans<<endl; } return 0; }