题目大意
有一个两面为空的硬币,正面和反面有区别。
你需要甩kk次,每次其会有一面朝上,如果该面为空,你填一个整数上去,若不为空,获得该分数。
你希望最大化分数和为的概率。
做法
如果s mod k=0s mod k=0显然我们不管哪面都会填s/ks/k,输出2k2k。
你能决定的是第一次摇到第2个面时,根据这是第几次决定另一面填啥。设这个为yy,第一次填上去的就是,那么xx是定值,你要提前准备。
下面我们令表示正面,yy表示反面(实际上由于正反面有区别,答案要乘2)。
设有次出现正面。
那么要满足Ax+(k−A)y=SAx+(k−A)y=S。
显然要有(A,k−A)|S(A,k−A)|S即(A,k)|S(A,k)|S。
我们可以证明,存在一个xx,对于满足的AA,都存在一个对应满足Ax+(k−A)y=SAx+(k−A)y=S。
Ax+(k−A)y=SAx+(k−A)y=S。
(k−A)(y−x)=S−kx(k−A)(y−x)=S−kx。
由于AA与对称可以得到A|S−kxA|S−kx。
所以有lcm(A)|S−kxlcm(A)|S−kx。
令lcm(A)∗p+kx=Slcm(A)∗p+kx=S。
我们知道一个简单的结论:
如果(a,c)|d,(b,c)|d,那么有([a,b],c)|d(a,c)|d,(b,c)|d,那么有([a,b],c)|d。这个结论的证明可以考虑从gcd以及lcm的本质出发,即对质因子次数取min与取max。
那么因为每个AA都满足于是有(lcm(A),k)|S(lcm(A),k)|S。
因此我们证明了这个xx一定存在。
接下来就好做了,答案是
事实上这个kk开到10^5当然也是能做的。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=60+10;
ll c[maxn][maxn];
int i,j,k,l,n,m,s;
ll ans,t;
class BearEmptyCoin{
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
public:
ll winProbability(int K,int S){
k=K;
s=S;
if (s%k==0){
ans=1;
fo(i,1,k) ans*=2;
return ans;
}
c[0][0]=1;
fo(i,1,k){
c[i][0]=1;
fo(j,1,i) c[i][j]=c[i-1][j]+c[i-1][j-1];
}
ans=0;
fo(j,1,k-1){
t=0;
fo(i,0,k-j-1)
if (s%gcd(i+j,k)==0) t=max(t,c[k-j-1][i]);
ans+=t;
}
return ans*2;
}
} zlt;
int main(){
printf("%lld\n",zlt.winProbability(2,-49));
}