2023.8.11测试

xishanmeigao / 2023-08-12 / 原文

\[\text{暑假NOIP模拟赛-4} \]

为什么我天天挂分?????????

T1 数对

其实就是[ARC107D] Number of Multisets

简单容斥+莫反,但是最后10min才发现容斥写错了!!!!!

\(calc(l,r)\) 表示 \(x\in[1,l]\)\(y\in[1,r]\) 的答案,那么 \(ans=calc(r,r)-calc(l-1,r)-calc(r,l-1)+calc(l-1,l-1)\)

#include<bits/stdc++.h>
#define LL long long
using namespace std;

const int N=1000010;

int L,R;
int v[N],prime[N],tot,mu[N];
LL ans,sum[N];

void primes()
{
	mu[1]=1;
	for(int i=2; i<=1e6; i++)
	{
		if(!v[i])
		{
			v[i]=i;
			prime[++tot]=i;
			mu[i]=-1;
		}
		for(int j=1; j<=tot && prime[j]<=v[i] && prime[j]<=1e6/i; j++)
		{
			v[i*prime[j]]=prime[j];
			if(i%prime[j]==0)
				break;
			mu[i*prime[j]]=-mu[i];
		}
	}
	
	for(int i=1; i<=1e6; i++)
		sum[i]=sum[i-1]+(LL)mu[i];
}

LL calc(int n,int m)
{
	LL res=1LL*n*m;
	for(int l=1,r; l<=n; l=r+1)
	{
		r=min(n/(n/l),m/(m/l));
		res-=1LL*(n/l)*(m/l)*(sum[r]-sum[l-1]);
	}
	for(int i=2; i<=n; i++)
		res-=1LL*((n/i)+(m/i)-1);
	return res;
}

int main()
{
	primes();
	
	scanf("%d%d",&L,&R);
	ans=calc(R,R)-2*calc(L-1,R)+calc(L-1,L-1);
	
	printf("%lld\n",ans);
	
	return 0;
}

T2 小偷与警察

其实就是P4334 [COI2007] Policija

很好的点双练习题,逼我赶紧去恶补圆方树,需要赶紧修订图的连通性相关(Tarjan算法)

先跑一遍 \(\Tarjan\),求出所有割点和割边,这步一眼。对于不是割边的边或割点的点,询问时显然直接输出yes

对于割边和割点,边双缩点和点双缩点都要做一遍???

不用!我们惊奇地发现一条割边的两个端点一定是割点,所以可以直接将边的询问转化为点的询问

那现在问题变成了