NOIP analog 87 (multi school 20)

preface

The problem is not difficult, but I think there are some small details, and then there are 100 million cards..

I feel that I can't see the algorithm for the problem of Cartesian tree, and then pay too little attention to the details of code implementation, and the constant is a little large.

Pay attention next time.

T1 set mean

Problem solving ideas

The feeling should be a kind of water in the expectation question.

It's OK to look at the complexity of the scope, which is \ (n\times m \), and then look at the violence score, which should not be a problem.

Enumerate each operation, calculate the expected value of the currently fetched number, and then calculate the expected sum of the remaining numbers at the same time.

When calculating, remove the number of current numbers, that is, multiply by an inverse element and directly push it linearly.

code

#include<bits/stdc++.h>
using namespace std;
inline int read()	
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){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 N=1e5+10,M=2e7+10,mod=998244353;
int n,m,ans,base,sum,inv[M];
int main()
{
	freopen("mos.in","r",stdin); freopen("mos.out","w",stdout);
	n=read(); m=read(); inv[1]=1; for(int i=2;i<=n*m+1;i++) inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;
	for(int i=1,x;i<=n;i++) x=read(),sum=(sum+1ll*x*m%mod)%mod;
	for(int i=1,temp;i<=n*m;i++) temp=1ll*sum*inv[n*m-i+1]%mod,base=(base+temp)%mod,ans=(ans+1ll*base*inv[i+1])%mod,sum=(sum-temp+mod)%mod;
	printf("%d",ans);
	return 0;
}

T2 polyalkylene glycol

Problem solving ideas

It is also expected, but compared with the previous topic, it is a little more difficult, the boundary needs to be paid attention to, and there is the problem of accuracy.

We find it a little difficult to push, so we choose to push back, so that we can get the expected value of each step.

Assuming that the current interval is \ (L_i,R_i \), the expected value of the optimal strategy in the next several intervals is \ (p \).

Obviously, if the random number is in the range of \ ([l_, I, P] \), we will choose to try the next one. After all, the risk is relatively low.

Similarly, if the random number is in the interval of \ ((P, r_, I] \), we won't try the next one because it is risky.

So the expected value of this interval is:

\[\displaystyle p_i=\dfrac{p-L_i}{R_i-L_i}\times p+(1-\dfrac{p-L_i}{R_i-L_i})\times\dfrac{R_i+p}{2} \]

Just push back from the last one.

code

#include<bits/stdc++.h>
#define int long long
#define double long double
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){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 N=1e6+10;
int n;
double ans,l[N],r[N];
#undef int
int main()
{
	#define int long long
	freopen("pag.in","r",stdin); freopen("pag.out","w",stdout);
	n=read(); for(int i=1;i<=n;i++) l[i]=read(),r[i]=read();
	ans=(l[n]+r[n])/2.0;
	for(int i=n-1;i>=1;i--)
	{
		if(l[i]>=ans){ans=(l[i]+r[i])/2.0;continue;}
		if(r[i]<=ans||l[i]==r[i]) continue;
		ans=(ans-l[i])/(r[i]-l[i])*ans+(1-(ans-l[i])/(r[i]-l[i]))*(r[i]+ans)/2.0;
	}
	printf("%.5Lf",ans);
	return 0;
}

T3 Technical Intelligence Agency

Problem solving ideas

It really doesn't look like a Cartesian tree, but it seems that if the modulus is a prime number, you can directly monotone stack + prefix and pass through.

Then for this problem, the monotone stack + prefix and the burst sweep monotone stack can get a high score of 75 PTS code

It is found that for the maintenance of the maximum value, a large root Cartesian tree can be directly established, and then the information of the subtree can be merged each time.

The general approach is to maintain a sum in ascending or descending order with the increase of coordinates.

Assume that the current maximum value is \ (maxn \).

Do not calculate the sum on the left of the intermediate value \ (suf=L_1+L_1\times L_2+L_1\times L_2\times L_3 ·· \)

The sum to the right of the middle value is not counted \ (pre=R_1+R_1\times R_2+R_1\times R_2\times R_3 ·· \)

So the contribution of the current point is \ ((suf+1)\times(pre+1)\times maxn^2 \)

For information merging, it is good to maintain the product of numbers in a subtree.

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
#define ls son[x][0]
#define rs son[x][1]
using namespace std;
inline int read()	
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
namespace GenHelper
{
	unsigned z1, z2, z3, z4, b;
	unsigned rand_()
	{
		b = ((z1 << 6) ^ z1) >> 13;
		z1 = ((z1 & 4294967294U) << 18) ^ b;
		b = ((z2 << 2) ^ z2) >> 27;
		z2 = ((z2 & 4294967288U) << 2) ^ b;
		b = ((z3 << 13) ^ z3) >> 21;
		z3 = ((z3 & 4294967280U) << 7) ^ b;
		b = ((z4 << 3) ^ z4) >> 12;
		z4 = ((z4 & 4294967168U) << 13) ^ b;
		return (z1 ^ z2 ^ z3 ^ z4);
	}
}
const int N=1e7+10;
int n,ans,top,root,mod,sta[N],s[N],son[N][2],pre[N],suf[N],bas[N];
void init()
{
	using namespace GenHelper;
	int L,R,cnt=0; unsigned S;
	n=read(); S=read(); L=read(); R=read();
	z1 = S;
	z2 = unsigned((~S) ^ 0x233333333U);
	z3 = unsigned(S ^ 0x1234598766U);
	z4 = (~S) + 51;
	for (int i = 1; i <= n; i++)
	{
		int x = rand_() & 32767;
		int y = rand_() & 32767;
		s[++cnt]=L + (x * 32768 + y) % (R - L + 1);
	}
}
void dfs(int x)
{
	bas[x]=s[x];
	if(ls) dfs(ls),bas[x]=bas[x]*bas[ls]%mod;
	if(rs) dfs(rs),bas[x]=bas[x]*bas[rs]%mod;
	ans=(ans+(suf[ls]+1)*(pre[rs]+1)%mod*s[x]%mod*s[x])%mod;
	pre[x]=(pre[ls]+bas[ls]*s[x]%mod*(pre[rs]+1)%mod)%mod;
	suf[x]=(suf[rs]+bas[rs]*s[x]%mod*(suf[ls]+1)%mod)%mod;
}
#undef int
int main()
{
	#define int long long
	freopen("tio.in","r",stdin); freopen("tio.out","w",stdout);
	init(); mod=read();
	for(int i=1;i<=n;i++)
	{
		while(top&&s[sta[top]]<s[i]) son[i][0]=sta[top--];
		if(top) son[sta[top]][1]=i; sta[++top]=i;
	}
	while(top) root=sta[top--]; bas[0]=1; dfs(root);
	printf("%lld",ans);
	return 0;
}

T4 KFC

Problem solving ideas

It's hard not to remember zxb the question of memory.

For 80pts, it can be calculated with tolerance and exclusion, and the tolerance and exclusion coefficient is \ (\ mu(i) \).

\[\displaystyle ans=\sum \mu(i)\times i^2\times \dfrac{\lfloor\frac{n}{i^2}\rfloor\times(\lfloor\frac{n}{i^2}\rfloor+1)}{2} \]

Considering optimization, it is found that the last item can be divided into blocks. At the same time, it is good to prefix and sum \ (\ mu(i)\times i^2 \).

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()	
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){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 N=1e7+10;
int T,cnt,pri[N],mu[N];
ull ans,n,pre[N];
bool vis[N];
inline void pre_work(int lim)
{
	mu[1]=1;
	for(int i=2;i<=lim;i++)
	{
		if(!vis[i]) pri[++cnt]=i,mu[i]=-1;
		for(int j=1;j<=cnt&&pri[j]*i<=lim;j++)
		{
			vis[pri[j]*i]=true;
			if(i%pri[j]) mu[pri[j]*i]=-mu[i];
			else break;
		}
	}
	for(int i=1;i<=lim;i++) pre[i]=pre[i-1]+mu[i]*i*i;
}
inline ull mul(ull x){if(x&1) return (x+1)/2*x;return x/2*(x+1);}
inline void solve()
{
	n=read(); ans=mul(n);
	for(ull l=2,r;l*l<=n;l=r+1)
	{
		r=sqrt(n/(n/(l*l)));
		ull temp=n/(l*l),num=mul(temp);
		ans+=(pre[r]-pre[l-1])*num;
	}
	printf("%llu\n",ans);
}
#undef int
int main()
{
	#define int long long
	freopen("kfc.in","r",stdin); freopen("kfc.out","w",stdout);
	pre_work(10000000); T=read(); while(T--) solve(); return 0;
}

Posted on Mon, 01 Nov 2021 09:46:31 -0400 by Giri J