首页 > 其他分享 >NOIP模拟(flandre、meirin、sakuya、scarlet) - 模拟赛总结

NOIP模拟(flandre、meirin、sakuya、scarlet) - 模拟赛总结

时间:2024-11-05 20:42:27浏览次数:3  
标签:sakuya NOIP int sum sdis long scnt fa 模拟

flandre

做得挺久的,大约做了 \(\rm 1h+\)。

首先,选出来的序列一定是升序的,因为交换升序序列中的任意两个都不可能让「感觉效果」更高。

然后来看选那些数组成这个序列。

接下来是我赛时的想法:

如果全为正数,那么自然正数全部都得选。需要考虑的是负数的情况。

首先,选择一个负数不仅会影响到「真实效果」比它大的烟花的「感觉效果」,比它小的也会影响,两边都有后效性,所以无法通过枚举来动态规划或贪心。

设当前已经选了的序列为 \(c_1,c_2,\dots,c_m\) 且已经有序(升序),那么当判断是否要加入一个新的数 \(c_0\) 时,假如选它不能让总「感觉效果」更大,那么「真实效果」小于等于 \(c_0\) 的更不行(可能的额外「感觉效果」一样,「真实效果」却不大于 \(c_0\))。

反之,要让「真实效果」小于等于 \(c_0\) 的烟花也能有有效贡献,\(c_0\) 就必须要选,这样才能补齐这些烟花的额外「感觉效果」来让它们有效。

最后,如果选择的序列中间空了一段,那么把这空的一段补齐贡献一定为正,因为这一空段的贡献一定大于已选的较小的一段的贡献,既然那一段都可以选,这一段当然也可以选。

综上所述,在排序后,所选的序列一定是靠右(「真实效果」较大)且连续的

所以直接从大到小扫描,处理出如果选了 \(a_i\) 所得到的 \(b_i\)(在 \(a\) 值比自己大的所有烟花都被选了的前提下),然后从右往左找最大前缀和即可。

另外,连续相等的不能互相做出贡献,这个要注意。

(因为变量初始化错了 + 可恶的 Subtask 评测方式炸了 \(30\) 分,恶心!)

#include<cstdio>
#include<algorithm>
using namespace std;

namespace IO{

int read()
{
	int x=0; bool neg=false;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') neg=true;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<3)+(x<<1)+(ch^'0');
		ch=getchar();
	}
	return neg?-x:x;
}
int sta[55];
void write_u(unsigned int x)
{
	int statop=0;
	while(x)
	{
		sta[++statop]=x%10;
		x/=10;
	}
	while(statop)
		putchar('0'+sta[statop--]);
	return;
}

}

const int N=1e6+5;
int n;
pair<long long,int> a[N];
long long k,b[N],sum[N];

int main()
{
	freopen("flandre.in","r",stdin);
	freopen("flandre.out","w",stdout);
	
	scanf("%d%lld",&n,&k);
	for(int i=1;i<=n;i++)
	{
		a[i].first=IO::read();
		a[i].second=i;
	}
	sort(a+1,a+n+1);
	int end=n+1; //应当初始化为n+1而非n!(下同)
	for(int i=n;i>=1;i--)
	{
		if(a[i].first!=a[i+1].first) end=i+1;
		b[i]=a[i].first+k*(n-end+1);
	}
	long long mxsum=0; int mxpos=n+1;
	for(int i=n;i>=1;i--)
	{
		sum[i]=sum[i+1]+b[i];
		if(sum[i]>mxsum)
		{
			mxsum=sum[i];
			mxpos=i;
		}
	}
	printf("%lld %d\n",mxsum,n-mxpos+1);
	for(int i=mxpos;i<=n;i++)
	{
		IO::write_u(a[i].second);
		putchar(' ');
	}
	return 0;
}

meirin

赛时最后 \(20\) 分钟把 \(40\) 分所需的公式出来了,虽然我也不太会证,但还是把我辛辛苦苦凑出来的式子贴在这里:

设 \(f_i\) 表示以 \(i\) 为右端点时的答案(就是题目公式里的 \(r=i\) 时的和),

\[f_i \ = \ f_{i-1} \ + \ a_i \times \sum_{j=1}^{i-1}b_j \ + \ b_i \times \sum_{j=1}^{i-1}a_j \ + \ j \times a_i \times b_i \]

答案就是 \(\sum_{i=1}^{n}f_i\),时间复杂度 \(O(QN)\)。

代码(\(40\) 分):

点击查看代码
#include<cstdio>
#define updmod(x) x=((x)%P+P)%P
using namespace std;

const int N=5e5+5,P=1000000007;
int n,q,a[N],b[N];
long long f[N];

int main()
{
	freopen("meirin.in","r",stdin);
	freopen("meirin.out","w",stdout);
	
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),updmod(a[i]);
	for(int i=1;i<=n;i++) scanf("%d",&b[i]),updmod(b[i]);
	for(int i=1;i<=q;i++)
	{
		int pl,pr,pk; scanf("%d%d%d",&pl,&pr,&pk);
		for(int j=pl;j<=pr;j++)
			b[j]+=pk,updmod(b[j]);
		long long ans=0,suma=0,sumb=0;
		for(long long j=1;j<=n;j++)
		{
			f[j]=f[j-1]+a[j]*sumb%P+b[j]*suma%P+j*a[j]%P*b[j]%P; updmod(f[j]);
			suma+=j*a[j],sumb=sumb+j*b[j]; updmod(suma),updmod(sumb);
			ans+=f[j]; updmod(ans);
		}
		printf("%lld\n",ans);
	}
	return 0;
}

正解是数学推式子,但是待定系数那一步我不太能想得到,后面的其实看起来都蛮好推的。

我的代码:

#include<cstdio>
#define updmod(x) x=((x)%P+P)%P
using namespace std;

const int N=5e5+5,P=1000000007;
int n,q,a[N],b[N];
long long prea[N],sufb[N];
long long fl[N],fr[N],f[N],sumf[N];

int main()
{
	freopen("meirin.in","r",stdin);
	freopen("meirin.out","w",stdout);
	
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),updmod(a[i]);
	for(int i=1;i<=n;i++) scanf("%d",&b[i]),updmod(b[i]);
	
	long long ans=0,suma=0,sumb=0,now=0;
	for(long long i=1;i<=n;i++)
	{
		now+=a[i]*sumb%P+b[i]*suma%P+i*a[i]%P*b[i]%P;
		suma=(suma+i*a[i])%P,sumb=(sumb+i*b[i])%P;
		ans=(ans+now)%P;
	}
	
	for(int i=1;i<=n;i++) prea[i]=(prea[i-1]+1ll*i*a[i])%P;
	for(int i=n;i>=1;i--) sufb[i]=(sufb[i+1]+1ll*(n-i+1)*a[i])%P;
	for(int i=1;i<=n;i++)
	{
		fl[i]=((fl[i-1]-prea[i-1])%P+P)%P,fr[i]=(fr[i-1]+sufb[i])%P;
		f[i]=(fl[i]+fr[i])%P; sumf[i]=(sumf[i-1]+f[i])%P;
	}
	
	for(int i=1;i<=q;i++)
	{
		int pl,pr,pk; scanf("%d%d%d",&pl,&pr,&pk);
		ans+=pk*(sumf[pr]-sumf[pl-1])%P;
		updmod(ans); printf("%lld\n",(long long)ans);
	}
	return 0;
}

sakuya

不会,考场上打的暴力,但是题目数据不讲“入德”,明明说暴力有 \(20\) 分的,结果只有 \(15\) 分,哼

标签:sakuya,NOIP,int,sum,sdis,long,scnt,fa,模拟
From: https://www.cnblogs.com/jerrycyx/p/18528688

相关文章

  • [61] (多校联训) A层冲刺NOIP2024模拟赛18
    无论从什么意义上都能称得上挂75分的一场A.选彩笔好题答案显然可以二分突然发现我好像专长二分答案钦定最大差值\(dx\),将所有物品以\((r,g,b)\)看成三维空间坐标内的点,原问题可以转化成问空间里一个边长为\(dx\)的立方体内是否有至少\(k\)个点考虑到值域不大,可......
  • 【某NOIP模拟赛T2 - 旅游】--线段树优化 DP 的魅力
    题意:数轴上在起点\(s\)和终点\(t\)间的整点中有\(n\)个关键点,第\(i\)个关键点位置为\(c_i\),可获得\(m_i\)的价值。你可以从起点开始,每次跳至多\(z\)个点(跨过中间的点),而每到达一个\(s\)以外的点需要支付\(a\)的代价,求走到终点的最大价值。\(0\les\lec_i\let......
  • noip模拟赛6
    A选彩笔(rgb)一眼转三维坐标系搞。但是最开始想歪了,以为要转曼哈顿距离,但是发现三维切比雪夫距离不支持转曼哈顿距离。补充一个知识点\(x\)维的曼哈顿距离支持转到\(2^{x-1}\)维的切比雪夫距离所以一维和二维可以直接转化,但是三维及以上就不行了。三维曼哈顿距离等同于某......
  • [DMY]2024 NOIP 模拟赛 Day 4
    不会暴搜不会差分约束不会三维DP不会根号分治不会卡常……赛时电脑没网,换了一台。T1看不懂题面,还以为是\(n-x\),然后有人给我说根据题目名称可以推断是\(n\%x\)。……[从现在开始到T2,我写完了,但是被人用手势删了,没保存,不想重新写了,所以就这样了]……T2赛后发现差分约束......
  • 【洛谷 P3695 CYaRon!语】从一道大模拟入坑自制编程语言
    原题传送门本来是想投题解的,但是仔细阅读了一下主题库题解规范,发现这篇文章更加适合单独作为一篇blog阅读而非挂在题解区里污染环境,所以就这样了。0xff开始之前这道题我很早以前就开始看了,那时还只有星野梦美大佬的一篇题解。而到现在,我终于是有了时间和能力来切掉这道题,......
  • NOIP
    noip考前专训(来自弱省弱校的挣扎)T1专训38题,在一个小时内写出正解。P11186三目运算体现出我不会递归的牛逼情况。照着题目模拟,类似对一段区间进行染色。因为递归成一颗二叉树形状,故从最深处返回的下标为紧挨下一次递归开始的下标。点击查看代码#ifdefONLINE_JUDGE......
  • P1088 [NOIP2004 普及组] 火星人
    [NOIP2004普及组]火星人题目描述人类终于登上了火星的土地并且见到了神秘的火星人。人类和火星人都无法理解对方的语言,但是我们的科学家发明了一种用数字交流的方法。这种交流方法是这样的,首先,火星人把一个非常大的数字告诉人类科学家,科学家破解这个数字的含义后,再把一个很小......
  • 【c++篇】:深入剖析vector--模拟实现属于自己的c++动态数组
    ✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨✨个人主页:余辉zmh–CSDN博客✨文章所属专栏:c++篇–CSDN博客文章目录前言一.`vector`类的默认成员函数整体框架构造函数析构函数拷贝构造函数赋值运算符重载函数测试二.`vector`......