CF366C题解
题目链接:Link
题目大意:
给定长度为
解题思路:
看到常规写法题解区已经有很多了,这里提供一种略微有些抽象的实现方式。
先讲讲思路,题目一眼 dp,于是开始看数据范围猜测一下时间复杂度,发现
于是开始观察题面,准备找一些可以乱搞的性质。发现对于
可以发现最大值并不是不可接受,于是便考虑使用一种极度抽象的做法,也就是对于序列
然后我们尝试对于两个序列进行配对,也就是枚举由
枚举可能和不难实现,这里记一个数组
配对也比较容易实现,这里不再多赘述,详细可以看代码。
代码如下:
#include<bits/stdc++.h>
#define lson pos<<1
#define rson pos<<1|1
#define ll long long
using namespace std;
const int maxn=1e2+10;
const ll mod=998244353;
int n,m,k;
int a[maxn],b[maxn];
int neg[maxn],pst[maxn];
int neg1[maxn],pst1[maxn];
int cnt1=0,cnt2=0;
int deli[100010],deli1[100010];
int stk[100010],stk1[100010];
struct node{
int id,sum;
}q[100010];
int main(){
//freopen("test.in","r",stdin);
//freopen("wjudge.out","w",stdout);
memset(deli,0,sizeof(deli));
memset(deli1,0,sizeof(deli1));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
int ans=0;
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
if(b[i]*m<a[i]) pst[++cnt1]=a[i]-b[i]*m,pst1[cnt1]=a[i];//分为不同的序列
else if(b[i]*m==a[i]) ans+=a[i];
else neg[++cnt2]=b[i]*m-a[i],neg1[cnt2]=a[i];
}
stk[0]=stk1[0]=0;
int tp=0,tp1=0;
for(int i=1;i<=cnt1;i++){
// cout<<pst[i]<<" ";
int r=0;
int tmp=tp;//这里防止单个数重复计算
for(int j=0;j<=tmp;j++){
//if(stk[j]+pst[i]==) cout<<endl<<stk[j]<<" "<<pst[i]<<endl;
if(deli[stk[j]+pst[i]]){//如果已经出现过这个和则更新最大值
if(deli[stk[j]+pst[i]]<deli[stk[j]]+pst1[i]){
q[++r].id=stk[j]+pst[i];
q[r].sum=deli[stk[j]]+pst1[i];
}
}
else{//没有出现就把新的和推进来
stk[++tp]=stk[j]+pst[i];
if(deli[stk[j]+pst[i]]<deli[stk[j]]+pst1[i]){
q[++r].id=stk[j]+pst[i];
q[r].sum=deli[stk[j]]+pst1[i];
}
}
}
for(int j=1;j<=r;j++) deli[q[j].id]=q[j].sum;
}
//cout<<deli[408]<<endl;
for(int i=1;i<=cnt2;i++){
// cout<<neg[i]<<" ";
int r=0;
int tmp=tp1;
for(int j=0;j<=tmp;j++){
// if(stk1[j]+neg[i]==342)cout<<endl<<stk1[j]<<" "<<neg[i]<<endl;
if(deli1[stk1[j]+neg[i]]){
if(deli1[stk1[j]+neg[i]]<deli1[stk1[j]]+neg1[i]){
q[++r].id=stk1[j]+neg[i];
q[r].sum=deli1[stk1[j]]+neg1[i];
}
}
else{
stk1[++tp1]=stk1[j]+neg[i];
if(deli1[stk1[j]+neg[i]]<deli1[stk1[j]]+neg1[i]){
q[++r].id=stk1[j]+neg[i];
q[r].sum=deli1[stk1[j]]+neg1[i];
}
}
}
for(int j=1;j<=r;j++) deli1[q[j].id]=q[j].sum;
}
int tmp=0;
for(int i=1;i<=tp;i++){//配对
if(deli1[stk[i]]) tmp=max(tmp,deli[stk[i]]+deli1[stk[i]]);//判断stk中出现的数在stk1中是否也出现过
}
//cout<<endl;
if(ans==0&&tmp==0) printf("-1");//是否有解
else printf("%d",tmp+ans);
return 0;
}
完结撒花 OvO!!!