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/i∗f[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
>
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>d)\end{cases}
f[pici]=⎩⎨⎧∑i=0cpi[(c−i+1)n−(c−i)n](c≤d)pd(c−d+1)n+∑i=0c−1pi[(c−i+1)n−(c−i)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);
}