(联考)noip87

T1

我是sb,考场推半天用当前A集合中的和来算贡献的式子,结果死活不对。

正解很简单....

每一个值对答案的贡献是一样的 \(\sum_{i=2}^{n\times m+1}inv_{i}\times(i-1)\) 所以直接算即可,最后再乘上\(inv_{n\times m}\)

T2

30pts:只能生成一个数,选最大的即可。

100pts:

期望要倒着推我是sb,设 \(f_{i}\) 表示后面 \(i\) 个的期望,已经算好后 \(i\) 个,那么只需跟当前的判断一下即可,大于就替换,否则继续枚举。

卡精度,要开long double 。

也是sb题

T3

考场一眼笛卡尔树,但不会维护区间乘积,于是死了....

40pts:直接暴力。

40+20pts:\(l=r\) 直接推一下式子就行。

80pts:用线段树维护区间乘积,\(O(n\log{n})\)

100pts:

建一颗大根堆笛卡尔树,dfs一遍,从下往上合并信息。

设每个点管辖的区间为 \([l,r]\) ,对于每个点都维护一个 \(pre_{i},suf_{i},pi_{i}\) 分别表示 \(\sum_{i=l}^{r}\prod_{j=l}^{i}a_{j},\sum_{i=r}^{l}\prod_{j=r}^{i}a_{j},\prod_{i=l}^{r}a_{i}\)

设点 \(ls_{i},rs_{i}\) 分别为 \(i\) 的左儿子和右儿子。

那么由 \(ls_{i},rs_{i}\) 向上合并到点 \(i\) 时,由于点 \(i\) 管辖的区间 \([l,r]\) 是由 \([l_{ls_{i}},r_{ls_{i}}]+[i,i]+[l_{rs_{i}},r_{rs_{i}}]\) 得来,所以有:

\[\begin{aligned} &pi_{i}=pi_{ls_{i}}\times a_{i}\times pi_{rs_{i}} \\ &pre_{i}=pre_{ls_{i}}+pre_{ls_{i}}\times a_{i}+pi_{ls_{i}}\times a_{i}\times pre_{rs_{i}} \\ &suf_{i}=suf_{rs_{i}}+suf_{rs_{i}}\times a_{i}+pi_{rs_{i}}\times a_{i}\times suf_{ls_{i}} \end{aligned} \]

自己画个图就不难理解

特殊的,如果点 \(i\) 为叶子节点,则 \(pi_{i}=pre_{i}=suf_{i}=a_{i}\)

那这题就没了...

Code
#include<cstdio>
#include<cctype>
#include<vector>
#define re register
const int MAX = 1e7+3;
#define long long long
#define scanf oma=scanf
#define freopen file=freopen
int oma;
FILE* file;
namespace some
{
	struct stream
	{
		template<typename type>inline stream &operator >>(type &s)
		{
			bool w=0; s=0; char ch=getchar();
			while(!isdigit(ch)){ w|=ch=='-'; ch=getchar(); }
			while(isdigit(ch)){ s=(s<<1)+(s<<3)+(ch^48); ch=getchar(); }
			return s=w?-s:s,*this;
		}
	}cin;
	int ans;
	int n,s,l,r,mod;
	int a[MAX],cnt;
	#define debug(s) printf("%s\n",s)
	auto max = [](int a,int b) { return a>b?a:b; };
}using namespace some;
namespace GenHelper
{
    unsigned z1, z2, z3, z4, b;
	auto rand_ = []() -> unsigned
	{
        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);
    };
} // namespace GenHelper
void get (int n, unsigned s, int l, int r) {
    using namespace GenHelper;
    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;
		a[++cnt] = l+(x*32768+y)%(r-l+1);
    }
}
namespace simple
{
	int mul,xam;
	auto solve = []() -> void
	{
		for(re int i=1; i<=n; i++)
		{
			mul = 1,xam = 0;
			for(re int j=i; j<=n; j++)
			{ mul = 1ll*mul*a[j]%mod,xam = max(xam,a[j]),(ans += 1ll*mul*xam%mod) %= mod; }
		}
		printf("%d\n",ans);
	};
};
namespace subtask
{
	auto task = [](int mi = 1) -> void
	{
		for(re int i=1; i<=n; i++)
		{ mi = 1ll*mi*l%mod,(ans += 1ll*(n-i+1)*mi%mod*l%mod) %= mod; }
		printf("%d\n",ans);
	};
};
namespace right
{
	int rt;
	long ans;
	struct Cartesian_Tree
	{
		int ch[MAX][2];
		int sta[MAX],top;
		long pre[MAX],suf[MAX],pi[MAX];
		#define ls(p) ch[p][0]
		#define rs(p) ch[p][1]
		void build()
		{
			pi[0] = 1;
			for(re int i=1; i<=n; i++)
			{
				while(top&&a[sta[top]]<a[i])
				{ ls(i) = sta[top--]; }
				if(top)
				{ rs(sta[top]) = i; }
				sta[++top] = i;
			}
			rt = sta[1];
		}
		void dfs(int p)
		{
			if(ls(p))
			{ dfs(ls(p)); }
			if(rs(p))
			{ dfs(rs(p)); }
			pi[p] = pi[ls(p)]*pi[rs(p)]%mod*a[p]%mod;
			if(!ls(p)&&!rs(p))
			{ pre[p] = suf[p] = a[p]; }
			else
			{
				pre[p] = (pre[ls(p)]+pi[ls(p)]*a[p]%mod+pi[ls(p)]*a[p]%mod*pre[rs(p)]%mod)%mod,
				suf[p] = (suf[rs(p)]+pi[rs(p)]*a[p]%mod+pi[rs(p)]*a[p]%mod*suf[ls(p)]%mod)%mod;
			}
			(ans += (suf[ls(p)]+1)*a[p]%mod*(pre[rs(p)]+1)%mod*a[p]%mod) %= mod;
		}
		void check()
		{
			for(re int i=1; i<=n; i++)
			//{ printf("%d %d\n",ch[i][0],ch[i][1]); }
			{ printf("pre=%lld suf=%lld %d\n",pre[i],suf[i],a[i]); }
		}
	}Tree;
	auto solve = []() -> void
	{
		Tree.build(),Tree.dfs(rt);
		//Tree.check();
		printf("%lld\n",ans);
	};
};
namespace OMA
{
	auto main = []() -> signed
	{
		freopen("tio.in","r",stdin); freopen("tio.out","w",stdout);
		cin >> n >> s >> l >> r >> mod; get(n,s,l,r);
		//if(l==r) { subtask::task(); }
		//else { simple::solve(); }
		right::solve();
		return 0;
	};
};
signed main()
{ return OMA::main(); }

T4

有个式子 \(\mu(n)^{2}=\sum_{d^{2}|n}\mu(d)\)

那这题就没了...

\[\begin{aligned} &\sum_{i=1}^{n}f_{i} \\ &=\sum_{i=1}^{n}\mu(i)^{2}\cdot i \\ &=\sum_{i=1}^{n}\sum_{d^{2}|i}\mu(d)\cdot i \\ &=\sum_{d=1}^{\sqrt{n}}\sum_{i=1}^{\left\lfloor\frac{n}{d^{2}}\right\rfloor}\mu(d)\cdot d^{2} \cdot i \\ &=\sum_{d=1}^{\sqrt{n}}\mu(d) \cdot d^{2}\sum_{i=1}^{\left\lfloor\frac{n}{d^{2}}\right\rfloor}i \end{aligned} \]

前边筛出来后求个前缀和,后边可以用整除分块解决。

取模直接用unsigned long long 自然溢出,但还是会乘爆,后边式子求和时注意/2的顺序即可。

posted @ 2021-11-02 07:24  -OMA-  阅读(65)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end