掌中之物,未必在掌握之中。|

2021hych

园龄:2年7个月粉丝:2关注:2

补题报告之S班暑训第六场

成绩

image

比赛经过

A 题,这啥鬼,怎么会有语法题,确认不需要高精度后,秒掉了,但是心里还是有些忐忑(咋会有这么入门的题?)。

B 题,原题啊?先想了一个 O(n3)DP,然后尝试找一找有没有决策单调性,发现关键贪心性质,开始码高精度,花了将近 1.5h。但是考后爆了,实际上洛谷上可以拿到 88 分的好成绩(因为 MLE 爆的)。

C 题,勰码作业题,简单的转换一下问题就秒了。

D 题,我去,傻瓜打表题,秒了。

赛后补题+分析

A 求和计算

简要/形式化题意

输入若干个数,求和。

题解

while 循环输入即可,语法题。

AC code

#include<bits/stdc++.h>
#define int long long 
using namespace std;
int x,sum;
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	while(cin>>x) {
		if(!x) {
			cout<<sum;
			break;
		}
		sum+=x;
	}
	return 0;
}

B 划分

简要/形式化题意

将一个序列分成若干区间,要求区间和不降,求所有区间和的平方的和的最小值。

题解

区间划分问题 dp 是第一个想到的,设 dpi,j 表示最后一段为 (j,i] 的最小值。那么有:

dpi,j=min0k<j,sumjsumksumisumj(dpk,j+(sumisumj)2)

这个显然是 O(n3) 的。不妨换个思路。

显然的,由数学归纳法不难证明分的段数越多越好。我们跳出 dp。如果我们把 dpi 当作前 i 个数的最小代价,optdeci 表示 i 的最优决策点(这个决策点的应该是满足条件的最大下标),就有:

x:=optdecj

optdeci=max0j<i,2×sumjsumxsumij

dpi=dpoptdeci+(sumisumoptdeci)2

显然的这是 O(n2) 的。对于 optdeci 的两个决策 k<j。对于 optdeci+1 显然 kj 也满足条件,也就是说 k 不可能成为最优决策。我们可以用单调队列维护 optdec 数组。然后就是 O(n) 的了。

考虑到空间问题,我们不用存储 dp 数组,只要从 n 利用 optdec 倒推即可。也不不必存储原数组,只要前缀和数组就好了。

最后是高精度,要用 int128

AC code

#include<bits/stdc++.h>
using namespace std;
const int N=4e7+10;
const int M=1e5+10;
const int mod=1<<30;
int n,type;
int x,y,z,m,val,p[M],l[M],r[M];
long long sum[N],b[N];
int h,t,q[N],opt_dec[N];
__int128 ans,delta;
void print(__int128 x) {
	if(x>9) print(x/10);
	putchar(x%10+'0'); 
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>type;
	if(!type) {
		for(int i=1;i<=n;i++) cin>>x,sum[i]=sum[i-1]+x; 
	}
	else {
		cin>>x>>y>>z>>b[1]>>b[2]>>m;
		for(int i=1;i<=m;i++) cin>>p[i]>>l[i]>>r[i];
		for(int i=3;i<=n;i++) b[i]=(x*b[i-1]+y*b[i-2]+z)%mod;
		for(int i=1;i<=m;i++)
			for(int j=p[i-1]+1;j<=p[i];j++) sum[j]=sum[j-1]+b[j]%(r[i]-l[i]+1)+l[i];	
	}
	h=t=1;
	for(int i=1;i<=n;i++) {
		while(h<t&&2*sum[q[h+1]]-sum[opt_dec[q[h+1]]]<=sum[i]) h++;
		opt_dec[i]=q[h];
		while(h<t&&2*sum[q[t]]-sum[opt_dec[q[t]]]>=2*sum[i]-sum[opt_dec[i]]) t--;
		q[++t]=i;
	}
	int dec=n;
	ans=0;
	while(dec) {
		delta=(__int128)(sum[dec]-sum[opt_dec[dec]]);
		delta=delta*delta;
		ans=ans+delta;
		dec=opt_dec[dec];
	}
	print(ans);
	return 0;
}

C 序列统计

简要/形式化题意

统计长度在 1n 之间,元素大小都在 lr 之间的单调不降序列的数量。

题解

i 的出现次数为 xi。问题等价于求。

1i=1rl+1xin

的正整数向量 (x1,x2,,xrl+1) 的非负整数解的个数。这是个经典结论的变形,答案为:

(rl+1+nn)1

Lucas 定理求解即可。

AC code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e6+3;
const int N=1e6+3;
int t,n,l,r,fact[N],inv[N];
void init() {
	fact[0]=inv[0]=1;
	fact[1]=inv[1]=1;
	for(int i=2;i<N;i++) {
		fact[i]=fact[i-1]*i%mod;
		inv[i]=(mod-mod/i)*inv[mod%i]%mod;
	}
}
int C(int n,int m,int p) {
	if(n<m) return 0;
	return fact[n]*inv[fact[m]]%p*inv[fact[n-m]]%p;
}
int Lucas(int n,int m,int p) {
	if(!m) return 1;
	return Lucas(n/p,m/p,p)*C(n%p,m%p,p)%p;
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>t;
	init();
	while(t--) {
		cin>>n>>l>>r;
		cout<<(Lucas(r-l+1+n,n,mod)-1+mod)%mod<<endl;
	}
	return 0;
}

D 最小等式

简要/形式化题意

求 |a o1 b o2 c o3 d| 的最小值, o1,o2,o3 均为四则运算符。要求算式的结果为整数。

题解

暴力打 64 个表排序即可,可以写一个循环打表把程序打出来,就不用人力打表了。

AC code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int a,b,c,d;
int ans[N],cnt;
void work(double x) {
	if(x==(int)(x)) ans[++cnt]=abs(x);
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>a>>b>>c>>d;
	work(a+b+c+d);
	work(a+b+c-d);
	work(a+b+c*d);
	work(a+b+c*1.0/d);
	work(a+b-c+d);
	work(a+b-c-d);
	work(a+b-c*d);
	work(a+b-c*1.0/d);
	work(a+b*c+d);
	work(a+b*c-d);
	work(a+b*c*d);
	work(a+b*c*1.0/d);
	work(a+b*1.0/c+d);
	work(a+b*1.0/c-d);
	work(a+b*1.0/c*d);
	work(a+b*1.0/c*1.0/d);
	work(a-b+c+d);
	work(a-b+c-d);
	work(a-b+c*d);
	work(a-b+c*1.0/d);
	work(a-b-c+d);
	work(a-b-c-d);
	work(a-b-c*d);
	work(a-b-c*1.0/d);
	work(a-b*c+d);
	work(a-b*c-d);
	work(a-b*c*d);
	work(a-b*c*1.0/d);
	work(a-b*1.0/c+d);
	work(a-b*1.0/c-d);
	work(a-b*1.0/c*d);
	work(a-b*1.0/c*1.0/d);
	work(a*b+c+d);
	work(a*b+c-d);
	work(a*b+c*d);
	work(a*b+c*1.0/d);
	work(a*b-c+d);
	work(a*b-c-d);
	work(a*b-c*d);
	work(a*b-c*1.0/d);
	work(a*b*c+d);
	work(a*b*c-d);
	work(a*b*c*d);
	work(a*b*c*1.0/d);
	work(a*b*1.0/c+d);
	work(a*b*1.0/c-d);
	work(a*b*1.0/c*d);
	work(a*b*1.0/c*1.0/d);
	work(a*1.0/b+c+d);
	work(a*1.0/b+c-d);
	work(a*1.0/b+c*d);
	work(a*1.0/b+c*1.0/d);
	work(a*1.0/b-c+d);
	work(a*1.0/b-c-d);
	work(a*1.0/b-c*d);
	work(a*1.0/b-c*1.0/d);
	work(a*1.0/b*c+d);
	work(a*1.0/b*c-d);
	work(a*1.0/b*c*d);
	work(a*1.0/b*c*1.0/d);
	work(a*1.0/b*1.0/c+d);
	work(a*1.0/b*1.0/c-d);
	work(a*1.0/b*1.0/c*d);
	work(a*1.0/b*1.0/c*1.0/d);
	sort(ans+1,ans+cnt+1);
	cout<<ans[1];
	return 0;
}

考后反思

希望 CCF 不要在考察选手对时间复杂度常熟系数的的把控(卡常真的很难搞)。当然,以后会尽量优化掉冗余步骤。

结尾

这场比赛感觉有点没质量啊(

本文作者:2021hych

本文链接:https://www.cnblogs.com/2021hych/p/17649640.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   2021hych  阅读(24)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起