2019.08.18【NOIP提高组】模拟 A 组

41 篇文章 0 订阅
24 篇文章 0 订阅

JZOJ 6309 完全背包

题目

完全背包模板,只是容量非常大,物品体积和价值特别小


分析

首先可以做一个10000大小的完全背包,然后枚举一份背包大小 i i i,那么由于体积特别小,其实可以选择 m / i ∗ f [ i ] + f [ m   m o d   i ] m/i*f[i]+f[m\bmod i] m/if[i]+f[mmodi],取最大值


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
typedef long long ll;
int f[10001],n,a[101]; ll ans,m;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
signed main(){
	freopen("backpack.in","r",stdin);
	freopen("backpack.out","w",stdout);
	n=iut(); scanf("%lld",&m);
	for (rr int i=1,x,y;i<=n;++i)
	    x=iut(),y=iut(),a[x]=max(a[x],y);
	for (rr int i=1;i<=100;++i) if (a[i])
	for (rr int j=i;j<=10000;++j)
	    f[j]=max(f[j],f[j-i]+a[i]);
	for (rr int i=1;i<=10000;++i)
	    ans=max(ans,m/i*f[i]+f[m%i]);
	return !printf("%lld",ans);
}

JZOJ 6308 中间值

题目

给定两个单调不下降的序列,带修改询问两个序列的某段区间合并后的中位数,保证修改后仍然单调不下降


分析

分治,考虑如果区间第 k k k大,那么可以先求出区间第 k / 2 k/2 k/2大,然后缩小区间分治解决


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
int n,m,a[2][500011];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline signed min(int a,int b){return a<b?a:b;}
inline signed pro(int l,int r,int L,int R,int k){
	if (l>r) return a[1][L+k-1];
	if (L>R) return a[0][l+k-1];
	if (k==1) return min(a[0][l],a[1][L]);
	rr int t=(k>>1)-1,mid1=min(l+t,r),mid2=min(L+t,R);
	return a[0][mid1]>a[1][mid2]?pro(l,r,mid2+1,R,k-mid2+L-1):pro(mid1+1,r,L,R,k-mid1+l-1);
}
signed main(){
	freopen("median.in","r",stdin);
	freopen("median.out","w",stdout);
	n=iut(); m=iut();
	for (rr int i=1;i<=n;++i) a[0][i]=iut();
	for (rr int i=1;i<=n;++i) a[1][i]=iut();
	while (m--){
		if (iut()&1){
			rr int x=iut(),y=iut();
			a[x][y]=iut();
		}else{
			rr int l=iut(),r=iut(),L=iut(),R=iut();
			print(pro(l,r,L,R,(r-l+R-L+3)>>1)),putchar(10);
		}
	}
	return 0;
}

JZOJ 6306 Sequence

题目

在这里插入图片描述


分析

首先把 B B B分解质因数,然后考虑 f f f,显然是一个积性函数,那么关键是如何求出 f ( p i c i ) f(p_i^{c_i}) f(pici),首先分类讨论,设 p i d i p_i^{d_i} pidi表示 B B B的质因数及其指数的幂
那么 f [ p i c i ] = { ∑ i = 0 c p i [ ( c − i + 1 ) n − ( c − i ) n ] ( c ≤ d ) p d ( c − d + 1 ) n + ∑ i = 0 c − 1 p i [ ( c − i + 1 ) n − ( c − i ) n ] ( c &gt; d ) \large f[p_i^{c_i}]=\begin{cases}\sum_{i=0}^cp^i[(c-i+1)^n-(c-i)^n](c\leq d)\\p^d(c-d+1)^n+\sum_{i=0}^{c-1}p^i[(c-i+1)^n-(c-i)^n](c&gt;d)\end{cases} f[pici]=i=0cpi[(ci+1)n(ci)n](cd)pd(cd+1)n+i=0c1pi[(ci+1)n(ci)n](c>d)
线性筛解决,但是在过程中注意取模


代码

#include <cstdio>
#include <cmath>
#define rr register
using namespace std;
typedef long long ll;
const int mod=998244353;
int ans,n,dp[20000101],prime[20000101],jc[31],cnt; bool v[20000101];
inline signed ksm(int x,int y){
	rr int ans=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
	    if (y&1) ans=1ll*ans*x%mod;
	return ans; 
}
inline signed mo(int a,int b){return a+b>=mod?a+b-mod:a+b;}
signed main(){
	rr ll kk,m;
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);
	scanf("%lld%d%lld",&kk,&n,&m);
	kk%=mod-1,jc[1]=ans=dp[1]=1;
	for (rr int i=2;i<=25;++i) jc[i]=ksm(i,kk);
	for (rr int i=2;i<=n;++i){
		if (!v[i]){
			prime[++cnt]=i; rr int tot=0;
			while (m%i==0) ++tot,m/=i;
			for (rr ll j=i,num=1,big=1,ls=dp[1];j<=n;j*=i,++num){
				v[j]=1,dp[j]=mo(1ll*ls*i%mod,mo(jc[num+1]-jc[num],mod));
				if (num<=tot) big=j,ls=dp[j];
				else dp[j]=mo(dp[j]-1ll*big*i%mod*mo(jc[num-tot]-jc[num-tot-1],mod)%mod,mod),
				     ls=dp[j],dp[j]=mo(dp[j],1ll*big*jc[num-tot]%mod);
			}
		}
		for (rr int j=1;prime[j]*i<=n&&j<=cnt;++j){
			if (i%prime[j]==0) break;
			for (rr ll k=prime[j];k<=n/i;k=k*prime[j])
			    if (!v[i*k]) v[i*k]=1,dp[i*k]=1ll*dp[i]*dp[k]%mod;
		}
		ans=mo(ans,dp[i]);
	}
	return !printf("%d",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值