2019.01.24【NOIP提高组】模拟 B 组

本文精选了解析洛谷OJ平台上的三道题目,包括超氧化钾、艰难的选择和人品问题。通过深入分析,提供了高效的算法解决方案,如等差数列求解、差分数组和动态规划。代码实现清晰,适合算法学习者参考。

JZOJ 3912 超氧化钾

题目

∑ i = 1 y x m o d    y \sum_{i=1}^yx \mod y i=1yxmody


分析

那么这道题其实高仿余数求和的题目,my 题解
那么首先这个式子可以改写成 x y − ∑ i = 1 y ⌊ x i ⌋ × i xy-\sum_{i=1}^y\lfloor\frac{x}{i}\rfloor\times i xyi=1yix×i
那么这个 ⌊ x i ⌋ \lfloor\frac{x}{i}\rfloor ix是有一定的频率的,那么中间的部分就可以省略掉了,所以说只要确定它的区间那么就可以用等差数列求解。
举个例子: x = 12 , y = 12 x=12,y=12 x=12,y=12
那么区间分别为 [ 1 ∼ 1 ] , [ 2 ∼ 2 ] , [ 3 ∼ 3 ] , [ 4 ∼ 4 ] , [ 5 ∼ 6 ] , [ 7 ∼ 12 ] [1\sim 1],[2\sim 2],[3\sim 3],[4\sim 4],[5\sim 6],[7\sim 12] [11],[22],[33],[44],[56],[712]
答案分别为 12 , 12 , 12 , 12 , 22 ( ⌊ 12 5 ⌋ ( 5 + 6 ) × ( 6 − 5 + 1 ) ÷ 2 ) , 57 ( ⌊ 12 7 ⌋ ( 7 + 12 ) × ( 12 − 7 + 1 ) ÷ 2 ) 12,12,12,12,22(\lfloor\frac{12}{5}\rfloor(5+6)\times (6-5+1)\div2),57(\lfloor\frac{12}{7}\rfloor(7+12)\times (12-7+1)\div2) 12,12,12,12,22(512(5+6)×(65+1)÷2),57(712(7+12)×(127+1)÷2)


代码

#include <cstdio>
#define rr register
using namespace std;
typedef unsigned long long ull;
ull x,y,ans;
signed main(){
	scanf("%llu%llu",&x,&y); ans=x*y;
	if (x<y) y=x;
	for (rr ull l=1,r;l<=y;l=r+1){
		r=x/(x/l); if (r>y) r=y;
		ans-=((l+r)*(r-l+1)>>1)*(x/l);
	}
	return !printf("%llu",ans);
} 

JZOJ 3903 艰难的选择

题目

找到一个最长的区间,使区间内0和1的个数相同


分析

首先今天打了一个二分,结果错漏百出,用自己做的数据测来测去都是错的,于是我无奈打了一个暴力,结果AC了,不过非正解,所以比赛结束后按照WYC的思路,也就是建立一个差分数组,再用一个桶记录最远且差分值相同的起点,再用终点减去起点即可


代码

#include <cstdio>
#include <cstring>
#define rr register
#define max(a,b) (((a)>(b))?(a):(b))
using namespace std;
int n,ans,v[200001];
signed main(){
	memset(v,-1,sizeof(v));
	scanf("%d",&n); v[n]=0;
	for (rr int i=1,s=0;i<=n;++i){
		rr char c=getchar();
		while (c!='0'&&c!='1') c=getchar();
		if (c=='0') --s; else ++s; 
	    if (v[s+n]<0) v[s+n]=i;
		    else ans=max(ans,i-v[s+n]);
	}
	return !printf("%d",ans);
} 

JZOJ 3914 人品问题

题目

在树上选择 k k k个点,要求这 k k k个点的父亲包含在 k k k个点中,根节点可以算作包含 k k k个点中,并使 k k k个点的点权和最大


分析

f [ x ] [ t ] f[x][t] f[x][t]表示节点为 x x x,在该子树选择 t t t个点的最大点权,那么 f [ x ] [ i ′ + j ′ + 1 ] = m a x { f [ i ] [ i ′ ] + f [ j ] [ j ′ ] + a [ x ] } f[x][i&#x27;+j&#x27;+1]=max\{f[i][i&#x27;]+f[j][j&#x27;]+a[x]\} f[x][i+j+1]=max{f[i][i]+f[j][j]+a[x]}


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
using namespace std;
int n,k,f[101][101],a[101],l[101],r[101],len[101];
inline signed iut(){
	rr int ans=0,f=1; rr char c=getchar();
	while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans*f;
}
inline signed max(int a,int b){return (a>b)?a:b;}
inline void dfs(int x,int dep){
	if (!x) return;
	dfs(l[x],dep+1),dfs(r[x],dep+1);
	for (rr int i=0;i<=len[l[x]];++i)
	for (rr int j=0;j<=len[r[x]];++j){
		if (i+j>k-dep) break;
		f[x][i+j+1]=max(f[x][i+j+1],f[l[x]][i]+f[r[x]][j]+a[x]);
	}
	len[x]=len[l[x]]+len[r[x]]+1;
}
signed main(){
	memset(f,-20,sizeof(f));
	n=iut(); k=iut()+1; f[1][0]=f[0][0]=0;
	for (rr int i=2;i<=n;++i) a[i]=iut(),f[i][0]=0;
	for (rr int i=1;i<=n;++i) l[i]=iut(),r[i]=iut();
	dfs(1,1); return !printf("%d",f[1][k]);
}

后续

话说今天洛谷是大凶

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值