列表

详情


NC206690. 见缝插针

描述

给一个圆形转盘,转盘被均匀划分成 个扇形,编号分别为 0,1,2.....,n-1。

现在我们需要投掷 根针。
游戏开始前,我们需要决定第 i 根针瞄准扇形 x_i,但是投掷出去后有 的概率投中 x_i,有 的概率投中扇形

注意选择的 x_i 需要两两不同,并且需要游戏开始前就决定好。

游戏开始后,每根针依次投出。若投完 k 根针后,每片扇形区域至多出现一根针,玩家获胜。
求玩家采取最优策略,获胜概率。可以证明答案是有理数可以表示成 的形式,在模 1000000007 意义下输出答案。

输入描述

第一行一个整数 ,表示 T 组数据。

接下来 T 行,每行两个整数

输出描述

输出 T 行,每行输出一个整数表示答案。

示例1

输入:

4
5 2
3 3
8 5
5 4

输出:

1
250000002
62500001
812500006

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 3ms, 内存消耗: 476K, 提交时间: 2020-05-24 17:56:06

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <map>
#include <stack>
#define ll long long
using namespace std;
const ll MOD=1000000007;
ll T,n,k;
ll 	ppo(ll x,ll p){
    ll t=x,res=1;
    while(p){
        if(p&1)res=(res*t)%MOD;  
        t=(t*t)%MOD; 
        p>>=1;
    }
    return res;
}
int main(){
	cin>>T;
	while(T--){
		cin>>n>>k;
		if(n==k){
			cout<<ppo(500000004,k-1)<<endl;
		}else if(n/2>=k){
			cout<<1<<endl;
		}else{
			ll xx=n-k;//空的点 == 堆数
			ll nn =(k)/xx;//每堆个数
			ll cnt = k%xx;//多出来的球 多 一 的堆数
			ll cnt2 =xx -cnt;//少一的个数
			ll ans=1;
			ans*=ppo((ppo(500000004,nn+1)*(nn+2))%MOD,cnt);
			ans%=MOD;
			ans*=ppo((ppo(500000004,nn)*(nn+1))%MOD,cnt2);
			ans%=MOD;
			cout<<ans<<endl;
		}
	}
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 3ms, 内存消耗: 376K, 提交时间: 2020-05-25 23:29:11

#include<iostream>
#include<cstdio>
typedef long long ll;
const ll mod=1e9+7;
ll qpow(ll x,ll y)
{
	x%=mod;
	ll res=1;
	for(;y;y>>=1,x=x*x%mod)
	if(y&1)
	res=res*x%mod;
	return res;
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		ll n,k;
		scanf("%lld%lld",&n,&k);
		if(n==k)
		printf("%lld\n",qpow(qpow(2,n-1),mod-2));
		else if(n>=k+k)
		printf("1\n");
		else
		{
			ll e=std::min(k,n-k),ans=0;
			ans=qpow(k/e+1,e-k%e)*qpow(k/e+2,k%e)%mod;
			printf("%lld\n",ans*qpow(qpow(2,k),mod-2)%mod);
		}
	}
	return 0;
}

上一题