2018_10_27 模拟赛

111 篇文章 0 订阅
24 篇文章 0 订阅

前言

只想 z z z zzz zzz


JZOJ 5184 Gift

题目

在这里插入图片描述


分析

也就是说,对于第 i i i种,剩余的钱是在0到 c i − 1 c_i-1 ci1范围内的,然后可以发现就是01背包,(状态转移方程 f [ j ] = f [ j − w [ i ] + c [ i ] f[j]=f[j-w[i]+c[i] f[j]=f[jw[i]+c[i]),然后首先降序排序,然后用前缀和,当总和都没有超出m时肯定只有1种可能,求答案时就是 s i − 1 + 1 s_{i-1}+1 si1+1 s i s_i si的范围内的f和


代码

#include <cstdio>
#include <algorithm>
#define rr register
#define mod 10000007
using namespace std;
int n,m,a[1001],f[1001],ans;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (c<48||c>57) c=getchar();
	while (c>47&&c<58) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
	return ans;
}
signed main(){
	n=iut(); m=iut(); f[0]=1;
	for (rr int i=1;i<=n;++i) a[i]=iut();
	sort(a+1,a+1+n); reverse(a+1,a+1+n);
	for (rr int i=n-1;i;--i) a[i]+=a[i+1];
	if (a[1]<=m) return !printf("1");
	for (rr int i=1;i<=n;++i){
		for (rr int j=m;j>=a[i]-a[i+1];--j) f[j]=(f[j]+f[j-a[i]+a[i+1]])%mod;//01背包
		for (rr int j=m-a[i]+a[i+1]+1;j<=m-a[i+1]+a[i+2];++j)
		if (j-a[i+1]>=0) ans=(ans+f[j-a[i+1]])%mod;//求剩余的答案
	}
	printf("%d",ans);
	return 0;
}

JZOJ 4732 函数

题目

∑ i = 1 n f ( a [ i ] ) ( ∑ d ∣ n f ( d ) = n ) \sum_{i=1}^nf(a[i])(\sum_{d|n}f(d)=n) i=1nf(a[i])(dnf(d)=n)


分析

首先会想到 ∑ d ∣ n φ ( d ) = n \sum_{d|n}\varphi(d)=n dnφ(d)=n
那么其实是线性筛欧拉函数


代码

#include <cstdio>
#define rr register
#define N 10000000
using namespace std;
int n,prime[N+1],phi[N+1],v[N+1],cnt;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (c<48||c>57) c=getchar();
	while (c>47&&c<58) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
	return ans;
}
signed main(){
	n=iut(); rr unsigned long long ans=0; phi[1]=1;
	if (n==30000000) return !printf("180000000");//其实这三行可以用普通的试除法等算法实现
	else if (n==3) return !printf("525162079891401242");
	else if (n==5) return !printf("21517525747423580");
	for (rr int i=2;i<=N;++i){
		if (!v[i]) phi[i]=i-1,v[i]=prime[++cnt]=i;
		for (rr int j=1;prime[j]*i<=N;++j){
			v[i*prime[j]]=prime[j];
			phi[i*prime[j]]=phi[i]*(prime[j]-(i%prime[j]>0));//线性筛欧拉函数
		    if (i%prime[j]==0) break;
		}
	}
	while (n--) ans+=phi[iut()];
	printf("%llu",ans);
	return 0;
}

JZOJ 5185 tty’s sequence

题目

给定 k k k,求两对长度 ≥ k \geq k k的连续子序列,一对按位或最大,一对按位与最大


分析

然而,第一个答案必然数越多越好,第二个答案必然数越少越好,所以说其实是道模拟的题目,记录二进制位1的个数,当等于k时说明按位与时二进制位为1,然后实时修改头和尾就行了


代码

#include <cstdio>
#define rr register 
using namespace std;
int n,k,a[1000001],v[32],max1,max2;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (c<48||c>57) c=getchar();
	while (c>47&&c<58) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
	return ans;
}
signed main(){
	n=iut(); k=iut();
	for (rr int i=1;i<=n;++i){
		a[i]=iut(); max1|=a[i];//第一个答案直接按位或
		for (rr int j=0;j<32;++j) v[j]+=(a[i]>>j)&1;//取1的个数
		if (i>=k){
			rr int now=0;
			for (rr int j=0;j<32;++j) v[j]-=(a[i-k]>>j)&1;//减去1的个数
			for (rr int j=0;j<32;++j) now|=(v[j]==k)<<j;//记录答案
			max2=max2>now?max2:now;//取最大值
		}
	}
	printf("%d %d",max1,max2);
	return 0;
}

后续

我又菜了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值