【JZOJ3318】Brunhilda的生日

65 篇文章 2 订阅
25 篇文章 0 订阅

description

除去对铁质盔甲强烈的热爱,Brunhilda是一个正常的7岁女孩。近期,她正在策划一个完美的生日派对。她发明了如下的一个游戏:所有的孩子在一个数k被宣读之前不停地跑来跑去。当这个数字k宣读后,所有的孩子将形成人数恰好为k的若干群体,且保证剩余的孩子数目小于k。最后,这不足k个的孩子将从游戏中被淘汰。紧接着,比赛将继续进行,并公布一个新的数字k。游戏将在所有的孩子都被淘汰后结束。

Brunhilda请她的父亲Wotan在游戏中来宣读数字。Wotan不喜欢这个游戏,当然也不希望在游戏的第一轮就宣布一个正无穷(PS:宣布正无穷等于将所有的孩子都从游戏中淘汰)。 Brunhilda认为这在派对上是相当尴尬的情形,所以她给了她父亲一串共计m个素数的列表。这样,她的父亲便可以从中进行选择。当然,相同的数字在游戏中可以被多次宣读。

Wotan想尽快结束比赛,因为他有一张他最喜欢的足球俱乐部 FC Asgard的比赛门票。不幸的是,Brunhilda不知道派对上参加游戏的孩子数目。现在,对于Q个不同的数n1,…,nQ个儿童,Wotan要预先知道他所需宣读的最少数字,以便他尽早结束游戏。


analysis

  • D P DP DP?暴力?

  • f [ i ] f[i] f[i]表示从后往前推 i i i的最小步数

  • 那么对于 i i i的某个质因子 p p p f [ i ] f[i] f[i]可转移到 f [ i + 1.. i + p − 1 ] f[i+1..i+p-1] f[i+1..i+p1]

  • 暴力搞出每个数存在的最大质因子

  • 可以知道 f f f单调不递减,于是 f f f肯定是一段一段的数且相差 1 1 1

  • 记录一下当前转移的左段点,枚举转移到可转移的右端点暴力转移

  • 每种情况只可能被一个数转移得到,那么均摊 O ( n ) O(n) O(n)

  • 一道傻逼题调的我自闭


code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 100005
#define MAX 10000000
#define INF 1000000007
#define ll long long
#define fo(i,a,b) for (ll i=a;i<=b;++i)
#define fd(i,a,b) for (ll i=a;i>=b;--i)

using namespace std;

ll maxp[MAX+5];
ll f[MAX+5],p[MAXN],ask[MAXN];
ll n,q,mx,left;

inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
inline ll min(ll x,ll y){return x<y?x:y;}
int main()
{
	n=read(),q=read();
	fo(i,1,n)p[i]=read(),maxp[p[i]]=p[i];
	fo(i,1,q)mx=max(mx,ask[i]=read());
	fo(i,1,n)for (ll j=p[i];j<=mx;j+=p[i])maxp[j]=p[i];
	memset(f,64,sizeof(f));
	fo(i,1,p[n]-1)f[i]=1;
	fo(i,1,mx)
	{
		if (maxp[i] && f[i]<INF)
		{
			fo(j,max(left,i+1),min(i+maxp[i]-1,mx))f[j]=min(f[j],f[i]+1);
		}
		left=max(left,i+maxp[i]-1);
	}
	fo(i,1,q)if (f[ask[i]]>INF)printf("oo\n");
		else printf("%lld\n",f[ask[i]]);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值