多校11

220(70+100+20+30) rank 53

T2:大模拟,而且相当简单

T1:数论,大数据质数快速确认

T3:思维题+高水平暴力水高分

T4:鬼畜的数位DP+位运算(考虑对每一位贡献)期望计算

T1:给你[L,R]区间,让你输出每个区间内数的最小质因子(R<=1e12)

记住结论!**对于一个数来说,如果是合数,一定存在一个在2根号这个数下的质因子**那么我们可以先把21e6下的质数筛出来,对每个质数筛一下它的在L,R范围内的倍数,标记合数,最后一边下来,被筛到·的数中取筛它的最小的质数就是质因子,没筛到的就是质数他自己

送命tips:long long能都开就都开,不然细节很要命

bool prime[1000000+100];ll l,r;
int zhi[1000000+100],cnt;
int bj=0;
inline void Prime()
{
	
	for(rint i=2;i<=bj;++i)
	{
		if(!prime[i])zhi[++cnt]=i;
		//chu("zhi[%d]:%d\n",cnt,zhi[cnt]);
		_f(j,1,cnt)
		{
			ll my=(ll)zhi[j]*i;
			if(my>(ll)bj)break;
			prime[my]=1;
			if(!(i%zhi[j]))break;
		}
	}
}
int is[2000000+100];
int main()
{
	scanf("%lld%lld",&l,&r);
	
	bj=sqrt(r+0.5);
	//chu("bj;%lld\n",bj);
	Prime();
	_f(i,1,2000000)is[i]=2147483647;
	for(int i=1;i<=cnt;++i)//zhi【i】
	{
		ll mx=r/zhi[i],mi=max(l/zhi[i],2LL);//这里也会变成long long所以都开long long比较好
	//	chu("%d --%d\n",mi,mx);
		for(ll j=mi;j<=mx;j++)//最多能凑出的
		{
			if((ll)j*zhi[i]<l)continue;
			is[(ll)j*zhi[i]-l+1]=min(zhi[i],is[(ll)j*zhi[i]-l+1]);
		}
	}
	for(ll i=l;i<=r;++i)
	{
		if(is[i-l+1]!=2147483647)chu("%d\n",is[i-l+1]);
		else chu("%lld\n",i);
	}

	return 0;
}

T3:给你n个数对(a,b),如果确定一种排列顺序,那么第i位的val值=max(val(i-1),sum_a[i])+b(i).求一种排列顺序,使得最大的val值最小

容易知道最大的val就是在最后一位,考虑构造一种方案,对于N=2,如果(a,b)(c,d)的顺序使得最大值更小,当而且仅仅当min(a,c)<min(b,d) [分类讨论一下就好,很容易证明]。那么进行推广,对于任意的n,只要按照这种顺序排队,那最后一定是一种最优解

思路纠正:我之前是只片面考虑了每两对数字之间,从前向后扫,有使得一个局部解更小的就换,但是首先因为序列在改变,所以前面换掉的更优可能被覆盖,其次局部更小对全局不一定,如果只从一个随机的顺序开始,很难弄出最优解,但是对于确定的序列,ans=sigma(sum_a[i]+sum_b[i])是对的(a前缀,b后缀)

部分分(1)当a=b,让第一个ai是最小的就行,因为上面的式子,自己画一个答案选集矩阵(2)当b=a+1,按照a升序是答案,考虑任意一对,如果交换,只可能答案不变或者答案增加,所以一定会更不优

c[i+4]=
ai+ bi +b[i+1]+b[i+2]+b[i+3]+b[i+4]
ai+a[i+1]+b[i+1]+b[i+2]+b[i+3]+b[i+4]
ai+a[i+1]+a[i+2]+b[i+2]+b[i+3]+b[i+4]
ai+a[i+1]+a[i+2]+a[i+3]+b[i+3]+b[i+4]
ai+a[i+1]+a[i+2]+a[i+3]+a[i+4]+b[i+4]

(3)DP也可以

int prime[1000000+100];ll l,r;
int zhi[1000000+100],cnt;
int bj=0;
inline void Prime()
{
	for(rint i=2;i<=bj;++i)
	{
		if(!prime[i])zhi[++cnt]=i,mi[i]=i;
		_f(j,1,cnt)
		{
			ll my=zhi[j]*i;
			if(my>(ll)r)break;
			prime[my]=1;
			mi[my]=zhi[j];
			if(!(i%zhi[j]))break;
		}
	}
}
int main()
{
	scanf("%lld%lld",&l,&r);
	bj=sqrt(r);
	Prime();
	for(ll i=l;i<=r;++i)
	{
		if(mi[i])
		{
			chu("%d\n",mi[i]);
		}
		else chu("%lld\n",i);
	}


	return 0;
}

T4:给你n,p,要求生成两个整数x,y在[0,n)之间,x随机等概率生成,y有p的概率,生成的数会使得x^y后尽量大,(1-p)的概率,也在[0,n)之间随机生成,求生成的数的值的期望

首先是P=0,只能生成随机的数,考虑每一位都是独立的,所以可以单独计算每一位是1的贡献,f[i]表示在x的选择数集合中i位是1的概率,ans1=\(\sum(2*f[i]*(1-f[i])*(1<<i)),0<=i<=bit\),怎么计算f[i]?;首先对于i位,从bit--i+1位如果没有满(n-1),就可以后面随便选,有(1<<i)种方法,使得i位是1,1~(i-1)都是任意;如果满了,那如果i本来是1,方案就是后面剩下的数的 个数,要注意因为本来就是(n-1)的数,所以+1-1的就消掉了

其次考虑P=1,只能生成使得最大的数ans2=\(\sum_{i=0}^{n-1}f[i]*i\),f[i]代表i^f[i]在[0,n)范围内最大。从高到低考虑每一位,i位:如果n-1是0,那么要让i位有贡献,就用没有贡献的减去有贡献的,没有贡献的就是(0,0)情况,不会有(1,1)的情况,因为如果x出现1,f[x]是1不仅更小而且值域更大,不“贪心”了,如果f[x]是0,而且必须是0,x还要是0,前面的f[x]只能贴n-1的边,不然f[x]选1一定比0更优,不“贪心”了,所以f[x]的方案是唯一的,对于x,如果x是0,前面的bit~i+1位的,不考虑本位的限制,n-1是0的地方,x可以是0或者1,(0就是满,1就是不满),但是n-1是1的地方,因为f【x】已经是1了,所以如果x再出现1就是(1,1)的非法组合,所以x在对应的贪心策略下只能是0,所以x的方案数是sum_0[i+1] ,sum_0[i+1]=\(\sum_{i=bit}^{0}\)((n-1)&(1<<i)==1),还有后面的x的部分,因为前面n-1是1的地方x是0所以x一定不满,就后面可以随便选,再*上(1<<i)

还有数位DP的做法就等着喵喵来帮我鎏!https://www.luogu.com.cn/problem/solution/P3898

还有为什么不是(n-1)(就是求p=0那块),若有可解惑者,重金悬赏10000000000000000000000000000000000000000000000000000000000000000个夜晚祝福你考上清北!!!

ll n;double p,f0[100];
int len,ps[100];
int main()
{
    //freopen("b.in","r",stdin);
   // freopen("b.out","w",stdout);
	n=re();scanf("%lf",&p);//先算随机的
	//dp[i]:表示i位出现1的概率
	//n/(2^(i+1))*2^i
	//max(n%2^(i+1)-2^i,0)
	double ans1=0,ans2=0;bool is=0;
	f_(i,59,0)
	{
		if(n&(1LL<<i))
		{
			is=1;
			ps[i]=ps[i+1];
		}
		else if(is)ps[i]=ps[i+1]+1;
		f0[i]=((n-1)>>(i+1))*(1LL<<i)   +    max((n%(1LL<<(i+1)))-(1LL<<i),0LL);
		f0[i]/=n;//就是i是1的概率
	}//pre[i]:最高到i位是0的个数
	//0:sigma(2*pi*(1-pi)*(1<<i))/n/n
	_f(i,0,60)ans2+=2*(f0[i])*(1.0-f0[i])*(1LL<<i);
	int bit=0;
	while((1LL<<(bit+1))<=(n-1))++bit;
	if((1<<bit)>(n-1))bit--;
	//chu("bit:%d\n",bit);
	f_(i,bit,0)
	{
		//chu("ps[%d]:%d\n",i,ps[i]);
		//chu("bit:%d\n",bit);
		if(((n-1)&(1LL<<i))>0)//是1
		{
			ans1+=(1LL<<i);
			//chu("ans1+=%lld\n",1LL<<i);
		}
		else ans1+=(double)(n-(1LL<<ps[i+1])*(1LL<<(i)))*(1LL<<(i))/(double)n;
	//	chu("an1;%lf\n",ans1);
	}
	ans1=ans1*p+ans2*(1-p);int ct=0;
	while(ans1>=10.0)ans1/=10.0,++ct;
	chu("%.5lf %d",ans1,ct);
	return 0;
}
posted on 2022-08-10 14:48  HZOI-曹蓉  阅读(28)  评论(0编辑  收藏  举报