【题解】CJOI2019 Oct 17 GZYZSY Round Day2 简要题解
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define getchar() (__c==__ed?(__ed=__buf+fread(__c=__buf,1,1<<18,stdin),*__c++):*__c++)
using namespace std; typedef long long ll; char __buf[1<<18],*__c=__buf,*__ed=__buf;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(!isdigit(c))f|=c==45,c=getchar();
while(isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const ll mod=20190816170251ll;
const int maxn=2e5+5;
vector<int> data[maxn];
pair<int,int> rnk[maxn];
int arc[maxn],n,m;
ll ans;
struct E{
ll sum; int x,y;
inline bool operator <(const E&a)const{return sum<a.sum;}
};
template<class qaq>
struct HEAP{
qaq data[maxn*3];
int cnt;
HEAP(){cnt=0;}
inline void up(const int&pos){
for(int t=pos;t>>1;t>>=1)
if(data[t>>1]<data[t]) swap(data[t],data[t>>1]);
else return;
}
inline void down(const int&pos){
for(int t=pos,k;(t<<1)<=cnt;t=k){
k=t<<1;
if(k<cnt&&data[k]<data[k|1]) k|=1;
if(data[t]<data[k])swap(data[t],data[k]);
else return;
}
}
inline void push(const qaq&tag){data[++cnt]=tag; up(cnt);}
inline void pop(){swap(data[1],data[cnt--]);down(1);}
inline const qaq&top(){return data[1];}
};
HEAP<E> q;
int main(){
#ifndef ONLINE_JUDGE
freopen("contain.in","r",stdin);
freopen("contain.out","w",stdout);
#endif
n=qr(); m=qr();
for(int t=1;t<=n;++t){
for(int g=qr();g;--g)
data[t].push_back(qr());
sort(data[t].begin(),data[t].end(),[&](int x,int y){return x>y;});
ans=ans+data[t][0];
if(data[t].size()==1) data[t].clear(),--t,--n;
}
sort(data+1,data+n+1,[&](const vector<int>&a,const vector<int>&b){return a[0]-a[1]<b[0]-b[1];});
--m;
q.push({ans-data[1][0]+data[1][1],1,1});
while(m--){
auto g=q.top();
int x=g.x,y=g.y;
q.pop();
ans=(ans*23333+g.sum)%mod;
if(y+1<data[x].size())
q.push({g.sum-data[x][y]+data[x][y+1],x,y+1});
if(x<n)
q.push({g.sum-data[x+1][0]+data[x+1][1],x+1,1});
if(x<n&&y==1)
q.push({g.sum+data[x][0]-data[x][1]-data[x+1][0]+data[x+1][1],x+1,1});
}
printf("%lld\n",ans);
return 0;
}
先放代码
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; typedef long long ll;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(!isdigit(c))f|=c==45,c=getchar();
while(isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=2e3+5;
int data[maxn];
namespace sol{
ll dp[maxn][maxn];
int stk[maxn][maxn];
int n,m,len;
inline int divd(int*x,ll*y,const ll&tag){
if(*x<=1) return *x;
int len=*x;
if(y[x[2]]-y[x[1]]>=tag*(x[2]-x[1])) return 1;
if(y[x[len]]-y[x[len-1]]<=tag*(x[len]-x[len-1])) return len;
int l=2,r=len-1,mid;
do{
mid=(l+r)>>1;
if(y[x[mid]]-y[x[mid-1]]<=tag*(x[mid]-x[mid-1])) l=mid+1;
else r=mid-1;
}while(l<=r);
return r;
}
inline void init(const int&a,const int&b){
n=a; m=b;
for(int t=1;t<=n;++t) data[t]=qr();
sort(data+1,data+n+1,[&](const int&a,const int&b){return a>b;});
memset(dp,0x3f,sizeof dp);
memset(stk,0,sizeof stk);
ll ans=dp[0][0];
dp[0][0]=0;
for(int t0=1;t0<=n;++t0){
dp[1][t0]=1ll*t0*data[t0];
for(int t=2;t<=m;++t){
int g=divd(stk[t-1],dp[t-1],data[t0]);
if(g) dp[t][t0]=dp[t-1][stk[t-1][g]]+1ll*(t0-stk[t-1][g])*data[t0];
}
ans=min(ans,dp[m][t0]);
for(int t=1;t<m;++t){
if(dp[t][t0]<=ans){
int*x=stk[t]; ll*y=dp[t];
while(*x&&y[x[*x]]>=ans) --*x;
while(*x>=2&&(long double)(y[x[*x]]-y[x[*x-1]])*(t0-x[*x-1])>=(long double)(y[t0]-y[x[*x-1]])*(x[*x]-x[*x-1])) --*x;
x[++*x]=t0;
}
}
}
printf("%lld\n",ans);
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("protect.in","r",stdin);
freopen("protect.out","w",stdout);
#endif
int T=qr(),a,b;
while(T--) a=qr(),b=qr(),sol::init(a,b);
return 0;
}