H题意:
将a数组排序。
定义dp[x],为将下标属于[1,x]内的元素进行若干次魔法达到的最小值。
则一个显然的想法是枚举i为终点,j为最后一次进行魔法的位置,
则有
d
p
[
i
]
=
{
j
∈
[
k
,
i
−
k
]
∣
m
i
n
(
d
p
[
j
]
−
a
[
j
+
1
]
)
+
a
[
i
]
}
dp[i]=\{j\in[k,i-k]\ |\ min(dp[j]-a[j+1])+a[i]\}
dp[i]={j∈[k,i−k] ∣ min(dp[j]−a[j+1])+a[i]};其中
i
∈
[
2
∗
k
,
n
]
i\in[2*k,n]
i∈[2∗k,n]
注意到转移时,第二层的枚举j可以直接拿一个变量代替,所以在转移时维护一个记录dp[i]-a[i+1]的最小值即可。
我当时很傻逼的掏了一个线段树出来维护这个,贼傻逼。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e5+7;
ll dp[maxn];
int a[maxn];
int main(){
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
sort(a+1,a+1+n);
for(int i=k;i<=min(n,k*2);++i) dp[i]=a[i]-a[1];
if(k*2<=n) dp[k*2]=min(dp[k*2],dp[k]+a[k*2]-a[k+1]);
ll pre=1e18;
for(int i=k;i<=k+1;++i) pre=min(pre,dp[i]-a[i+1]);
for(int i=k*2+1;i<=n;++i){
dp[i]=pre+a[i];
pre=min(pre,dp[i-k+1]-a[i-k+2]);
}
printf("%lld\n",dp[n]);
return 0;
}
I题意:
放假了,最近脑子不好。。。。
先对数组去重,一会说作用。
接下来考虑每一位,如果第x位上既有为1的数字,也有为0的数字存在,那么就一定是答案了,因为1的可以和0连接,0的可以和1连接,一条边的花费为(1<<x),当然需要注意的是之前去重,因为相同的数字连接起来花费为0,所有连接花费实际上是不同权值点的个数-1条边。
如果遍历完所有位发现无答案,那么说明所有数字均相同,答案为0。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+7;
typedef long long ll;
int a[maxn];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
sort(a+1,a+1+n);
n=unique(a+1,a+1+n)-a-1;
ll res=0;
for(int i=0;i<30;++i){
bool aa=0,b=0;
for(int j=1;j<=n;++j)
if(a[j]>>i&1) aa=1;
else b=1;
if(aa&&b){
res=(n-1LL)*(1<<i);
break;
}
}
printf("%lld\n",res);
return 0;
}
J题意:
手写几项展开,可以发现是一个连乘以及一个累和的相加。
题解很清晰:
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+7;
typedef long long ll;
const int mod=1e9+7;
ll one[maxn<<2|1];
ll two[maxn<<2|1];
ll K[maxn],B[maxn];
void pushup(int k){
one[k]=one[k<<1]*one[k<<1|1]%mod;
two[k]=(two[k<<1]*one[k<<1|1]+two[k<<1|1])%mod;
}
void build(int l,int r,int k){
if(l==r){
one[k]=K[l]%mod;
two[k]=B[l]%mod;
return ;
}
int mid=l+r>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
pushup(k);
}
void upd(int l,int r,int k,int id,int kk,int bb){
if(l==r){
one[k]=kk%mod;two[k]=bb%mod;
return ;
}
int mid=l+r>>1;
if(id<=mid) upd(l,mid,k<<1,id,kk,bb);
else upd(mid+1,r,k<<1|1,id,kk,bb);
pushup(k);
}
pair<ll,ll> ask(int l,int r,int k,int L,int R){
if(l>=L&&r<=R) return make_pair(one[k],two[k]);
int mid=l+r>>1;
if(L>mid) return ask(mid+1,r,k<<1|1,L,R);
if(R<=mid) return ask(l,mid,k<<1,L,R);
pair<ll,ll> x,y;
x=ask(l,mid,k<<1,L,R);
y=ask(mid+1,r,k<<1|1,L,R);
return make_pair(x.first*y.first%mod,(x.second*y.first+y.second)%mod);
}
int main(){
int n,m,l,r,id,x;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%lld",&K[i]);
for(int i=1;i<=n;++i) scanf("%lld",&B[i]);
build(1,n,1);
while(m--){
scanf("%d%d%d",&id,&l,&r);
if(id==1){
scanf("%d",&x);
upd(1,n,1,l,r,x);
}
else{
pair<ll,ll> rr=ask(1,n,1,l,r);
printf("%lld\n",(rr.first+rr.second)%mod);
}
}
return 0;
}