【JZOJ 省选模拟】6708.密码

题目

Description

在这里插入图片描述
Input
在这里插入图片描述

Output

在这里插入图片描述
Sample Input
5 3
0 100000000 200000000 700000000 0 0 0 0 0 0
0 600000000 150000000 250000000 0 0 0 0 0 0
0 333333333 333333334 333333333 0 0 0 0 0 0
0 0 0 450000000 550000000 0 0 0 0 0
0 999999998 1 1 0 0 0 0 0 0
123

Sample Output
0.004999999995000
0.090000000180000
0.000000000000000

Data Constraint
在这里插入图片描述

思路

考虑每个数字的贡献
每个位置找到一个最大的值,将这个最大值的字符找出来变成一
个字符串。预处理如果匹配出一段区间的位置的概率。
如果串m这里跟最大的概率的字符不同,那么这个概率一定小
于0.5,这样的点不会超过log个。
每次找到两个串的后缀的lcp,将匹配的概率乘起来,这样的操
作在log次之后就会小于1e-9。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=1e9+7,N=1e6+77;
const double eps=1e-9;
ll pre1[N],pre2[N],_10[N],a[N][11],b[N],c[N],n,m,yjy;
char st[N];
double aii[N],p;
char ch;
bool check(ll x,ll y,ll mid)
{
	ll u=(pre1[x+mid]-pre1[x-1]*_10[mid+1]%mod+mod)%mod,v=(pre2[y+mid]-pre2[y-1]*_10[mid+1]%mod+mod)%mod;
	if(u==v) return 1;
	return 0;
}
ll power(ll x,ll t)
{
	ll b=1;
	while(t)
	{
		if(t&1) b=b*x%mod;
		x=x*x%mod; t>>=1;
	}
	return b;
}
void init()
{
	for(int i=1; i<=n; i++)
	{
		yjy=0;
		for(int j=0; j<=9; j++)
		{
			scanf("%lld",&a[i][j]);
			if(a[i][j]>a[i][yjy]) yjy=j;
		}
		b[i]=yjy;
	}
	scanf("%s",st+1);
	for(int i=1; i<=n; i++) c[i]=st[i]-'0';
	_10[1]=10;
	for(int i=2; i<=n; i++) _10[i]=_10[i-1]*10%mod;
	for(int i=1; i<=n; i++) pre1[i]=(pre1[i-1]*10%mod+b[i])%mod;
	for(int i=1; i<=m; i++) pre2[i]=(pre2[i-1]*10%mod+c[i])%mod;
	for(int i=1; i<=m; i++) p=p*a[i][b[i]]/1000000000;
}
int main()
{
	freopen("password.in","r",stdin);freopen("password.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	p=1;
	init();
	for(int i=1; i<=n-m+1; i++)
	{
		int x=i,y=1;
		aii[i]=p;
		ll cnt=0;
		while(aii[i]>eps&&y<=m)
		{
			int l=-1,r=m-y-1;
			while(l<r)
			{
				int mid=(l+r+1)>>1;
				if(check(x,y,mid)==1) l=mid;else r=mid-1;
			}
			int s=l;
			aii[i]=aii[i]*a[x+s+1][c[y+s+1]]/a[x+s+1][b[x+s+1]];
			x=x+s+2,y=y+s+2;
			cnt++;
		}		
		p=p/a[i][b[i]]*a[i+m][b[i+m]];	
	}
	for(int i=1; i<=n-m+1; i++) printf("%.10lf\n",aii[i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值