多校冲刺 NOIP 20211030 模拟 (20)

T1 集合均值

送分题一个,好像线性筛求逆元比递推要快????因为我根本没有卡常来着。。。。

#include<bits/stdc++.h>
#define niuma (n*m+1)
#define int long long
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int maxn=1e5+5;
const int mod=998244353;
int n,a[maxn],m,inv[20000007],pr[20000007],cnt;
bool bo[20000007];
inline int ksm(int x,int y)
{
	int res=1;x=x%mod;
	for(;y;y>>=1){if(y&1)res=res*x%mod;x=x*x%mod;}
	return res;
}
inline void shai()
{
	inv[1]=1;
	for(int i=2;i<=niuma;i++)
	{
		if(!bo[i]){inv[i]=ksm(i,mod-2);pr[++cnt]=i;}
		for(int j=1;j<=cnt&&i*pr[j]<=niuma;j++)
		{
			bo[i*pr[j]]=1;
			inv[i*pr[j]]=inv[i]*inv[pr[j]]%mod;
			if(!(i%pr[j])) break;
		}
	}
}
signed main()
{
	freopen("mos.in","r",stdin);
	freopen("mos.out","w",stdout);
	n=read();m=read();shai();
	for(int i=1;i<=n;i++) a[i]=read();
	int sum=0,iv=ksm(n*m,mod-2);
	for(int i=n*m+1;i>=1;i--) {inv[i]=(inv[i+1]+inv[i])%mod;}
	for(int i=1;i<=n*m;i++) sum=(sum+(inv[i+1])%mod*iv%mod)%mod;
	int ans=0; for(int i=1;i<=n;i++)
	ans=(ans+a[i]%mod*sum%mod)%mod;
	cout<<ans*m%mod<<endl;
}

T2 聚烷撑乙二醇

这道题证明了我期望学的跟没学一样,期望明明要逆推,我正着推了一亿年没整出来,我就是个sb

我们设F[i]为只用第i个到第n个的期望数字是多少,很显然f[n]就是(r[i]+l[i])/2

然后从f[i+1]轻松得到f[i],就是看取出来一个数假如比f[i+1]小,那么就接着选后面的

否则就在大于f[i+1]到r[i]里面均匀分配(取平均值)

#include<bits/stdc++.h>
#define double long double
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int maxn=1e6+5;
const double eps=1e-9;
int n;
double l[maxn],r[maxn];
inline double ksm(double x,int y)
{
	double res=1;
	while(y){if(y&1)res=res*x;x=x*x;y>>=1;}
	return res;
}
double f[maxn];
signed main()
{
	freopen("pag.in","r",stdin);
	freopen("pag.out","w",stdout);
	n=read();bool flag=0;
	for(int i=1;i<=n;i++)
	{
		l[i]=read();
		r[i]=read();
		if(l[i]!=r[i])flag=1;
	}
	if(!flag)
	{
		double ans=0;
		for(int i=1;i<=n;i++)
		ans=max(ans,l[i]);
		printf("%.5Lf",(double)ans);
		return 0;
	}
	else
	{
		f[n]=(l[n]+r[n])/2.0;
		for(int i=n-1;i>=1;i--)
		{
			double len=r[i]-l[i];
			if(f[i+1]>=r[i]) f[i]=f[i+1];
			else if(f[i+1]<=l[i]) f[i]=(r[i]+l[i])/2.0;
			else f[i]=((f[i+1]-l[i])/len)*f[i+1]+((r[i]+f[i+1])/2)*(r[i]-f[i+1])/len;
		}
		printf("%.5Lf",f[1]);
	}
}

T3 技术情报局

首先想到的是一个分治的做法,主要是因为昨天做了这个题目,而且也比较好想,毕竟还要打对拍,就顺便写了下

先说一下分治的写法,首先对于区间l~r,我们的最大值不是在左边就是在右边;

我们可以强制让最大值在一侧,然后另一侧用单调指针扫着,然后顺便统计下答案

代码如下:

inline void msort(int l,int r)
{
	if(l==r){return ans=(ans+a[l]*a[l])%mod,void();}
	int mid=(l+r)>>1;msort(l,mid);msort(mid+1,r);
	int tmp=mid,maxx=0,sum=0,nw=1,wo=1;
	for(int i=mid;i>=l;i--)
	{
		maxx=max(a[i],maxx);wo=wo*a[i]%mod;
		while(a[tmp+1]<maxx&&tmp<r)
		{
			tmp++;nw=nw*a[tmp]%mod;
			sum=(sum+nw)%mod;
		}
		ans=(ans+maxx*wo%mod*sum%mod)%mod;
	}
	tmp=mid+1,maxx=0,sum=0,nw=1,wo=1;
	for(int i=mid+1;i<=r;i++)
	{
		maxx=max(a[i],maxx);wo=wo*a[i]%mod;
		while(a[tmp-1]<=maxx&&tmp>l)
		{
			tmp--;nw=nw*a[tmp]%mod;
			sum=(sum+nw)%mod;
		}
		ans=(ans+maxx*wo%mod*sum%mod)%mod;
	}
}

写着写着,我发现很多地方统计是重复的,偶然间想起来笛卡尔树,因为笛卡尔树上的元素以每个点为最大值的区间是包含关系的

所以我们可以将分治里面的合并转化为笛卡尔树里的子树进行合并

我们设val[x][1]为x管辖的区间全部贴紧右边界的区间乘积的和,val[x][0]是左边的

那么我们合并起来就会非常好写了

	ans=(ans+a[x]*a[x])%mod;val[x][0]=val[x][1]=a[x];sum[x]=a[x];
	if(ls)
	{
		dfs(ls);
		ans=(ans+(val[ls][1]*val[x][0]%mod*a[x]%mod))%mod;
		val[x][0]=(sum[ls]*val[x][0]+val[ls][0])%mod;
		val[x][1]=(sum[x]*val[ls][1]+val[x][1])%mod;
		sum[x]=sum[x]*sum[ls]%mod;
	}
	if(rs)
	{
		dfs(rs);
		ans=(ans+(val[rs][0]*val[x][1]%mod*a[x]%mod))%mod;
		val[x][0]=(val[rs][0]*sum[x]+val[x][0])%mod;
		val[x][1]=(val[x][1]*sum[rs]+val[rs][1])%mod;
		sum[x]=sum[x]*sum[rs]%mod;
	}

不过一开始以为内存只有512兆,担心会爆掉,所以写了个l==r的特判,结果内存开了2个G。。。

T4 肯德基

我是筛法超级弱者。。。。。

由于我太弱了,完全忘记了莫比乌斯函数就是天然的容斥系数,于是就爆砍30分。。。

n的范围是1e14,显然线性筛只需要筛的根号,然后容斥一下就好了。。。

\[ans=\sum\limits_{i=1}^{\sqrt{n}}\mu{(i)}i^2S(\left \lfloor \frac{n}{i^2} \right \rfloor) \]

\[s(i)=\sum\limits_{j=1}^{j<=i}j \]

#include<bits/stdc++.h>
#define ull unsigned long long
#define int long long
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int maxn=2e7+5;
bool bo[maxn];
int pr[maxn],mu[maxn],cnt;
int sum[maxn];
inline ull f(ull x)
{
	if(x&1) return (x+1)/2*x;
	else return x/2*(x+1);
}
inline void shai()
{
	mu[1]=1;
	for(int i=2;i<=1e7;i++)
	{
		if(!bo[i]){pr[++cnt]=i;mu[i]=-1;}
		for(int j=1;j<=cnt&&i*pr[j]<=1e7;j++)
		{
			bo[i*pr[j]]=1;
			if(!(i%pr[j])){mu[i*pr[j]]=0;break;}
			mu[i*pr[j]]=-mu[i];
		}
	}
	for(int i=1;i<=1e7;i++)	sum[i]=sum[i-1]+mu[i]*i*i;
}
signed main()
{
	freopen("kfc.in","r",stdin);
	freopen("kfc.out","w",stdout);
	shai();int t=read();
	while(t--)
	{
		int n=read();ull ans=0;
		for(int l=1,r;l*l<=n;l=r+1)
		{
			r=(int)sqrt(n/(n/(l*l)));
			ans+=(sum[r]-sum[l-1])*(int)f(n/(l*l));
		}
		cout<<ans<<endl;
	}
}
posted on 2021-11-01 15:46  JYFHYX  阅读(23)  评论(0编辑  收藏  举报