Deltix Round, Spring 2021 F,G 题解
Deltix Round, Spring 2021 F,G 题解
F
首先,只有任务点和传送门的位置是重要的。
所以可以另\(dp_{i,mask,j}\)表示当前在第\(i\)个位置,被经过的传送门的集合为\(mask\),达成了\(j\)个任务的最小时间。
这样直接转移时\(O(M^32^N)\)无法通过。
但是可以发现,如果在一个任务点则时间是知道的,只需要知道最多能达成多少任务。
所以可以优化一个\(M\)。
时间复杂度为\(M^22^N\)。
code:
/*
{
######################
# Author #
# Gary #
# 2021 #
######################
*/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
// int x=0;
// char ch=getchar();
// while(ch<'0'||ch>'9'){
// ch=getchar();
// }
// while(ch>='0'&&ch<='9'){
// x=(x<<1)+(x<<3)+(ch^48);
// ch=getchar();
// }
// return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MAXM=101;
const int MAXN=14;
LL dp[1<<MAXN][MAXM];
int f[1<<MAXN][MAXM];
int dis[1<<MAXN][MAXM],dis2[MAXM][MAXM],dis3[1<<MAXN][MAXN],xa[MAXN],ya[MAXN],xb[MAXM],yb[MAXM],t[MAXM],n,m;
bool cmp(pair<mp,int> A,pair<mp,int> B){
return A.SEC<B.SEC;
}
int main(){
scanf("%d%d",&n,&m);
rep(i,n) scanf("%d%d",&xa[i],&ya[i]);
rb(i,1,m) scanf("%d%d%d",&xb[i],&yb[i],&t[i]);
fill((LL*)dp,(LL*)dp+(1<<MAXN)*MAXM,1e18);
fill((int*)f,(int*)f+(1<<MAXN)*MAXM,-1e9);
vector<pair<mp,int> > inf(m+1);
rb(i,1,m) inf[i]=II(II(xb[i],yb[i]),t[i]);
sort(inf.begin()+1,inf.begin()+1+m,cmp);
rb(i,1,m) xb[i]=inf[i].FIR.FIR,yb[i]=inf[i].FIR.SEC,t[i]=inf[i].SEC;
// rb(i,1,m){
// cout<<xb[i]<<' '<<yb[i]<<" "<<t[i]<<endl;
// }
rep(mask,1<<n){
rb(k,1,m){
dis[mask][k]=INF;
rep(j,n){
if((mask>>j)&1){
check_min(dis[mask][k],abs(xb[k]-xa[j])+abs(yb[k]-ya[j]));
}
}
}
}
rep(mask,1<<n) rep(j,n){
dis3[mask][j]=INF;
rep(k,n)
if((mask>>k)&1)
check_min(dis3[mask][j],abs(xa[j]-xa[k])+abs(ya[j]-ya[k]));
}
rb(i,1,m)
rb(j,1,m)
dis2[i][j]=abs(xb[i]-xb[j])+abs(yb[i]-yb[j]);
rep(i,n) dp[1<<i][0]=0;
rb(i,1,m) f[0][i]=1;
rep(mask,1<<n){
rb(j,0,m){
if(f[mask][j]>=0){
rb(nex,j+1,m){
if(t[j]+min(dis2[j][nex],dis[mask][nex])<=t[nex]){
check_max(f[mask][nex],f[mask][j]+1);
}
}
rep(nex,n){
if((mask>>nex)&1);
else
check_min(dp[mask|(1<<nex)][f[mask][j]],1ll*t[j]+min(abs(xa[nex]-xb[j])+abs(ya[nex]-yb[j]),dis3[mask][nex]));
}
}
if(dp[mask][j]!=1e18){
rep(k,n){
check_min(dp[mask|(1<<k)][j],dp[mask][j]+dis3[mask][k]);
}
rb(nex,j+1,m){
if(dp[mask][j]+dis[mask][nex]<=t[nex]){
check_max(f[mask][nex],j+1);
}
}
}
}
}
int ans=0;
rb(i,1,m) rep(mask,1<<n) check_max(ans,f[mask][i]);
printf("%d\n",ans);
return 0;
}
G
诈骗题。。。
只要知道答案总和为\(n\sum_{i=1}^n \frac{1}{i}=O(n\log n)\),就会做了。
/*
{
######################
# Author #
# Gary #
# 2021 #
######################
*/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
// int x=0;
// char ch=getchar();
// while(ch<'0'||ch>'9'){
// ch=getchar();
// }
// while(ch>='0'&&ch<='9'){
// x=(x<<1)+(x<<3)+(ch^48);
// ch=getchar();
// }
// return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int N=1<<16;
int n,m,l[N<<1],r[N<<1];
set<mp> sgt[N+N];
vector<int> seg[N];
int query(int a,int b,int now=1,int l=1,int r=N+1){
if(r<=a||l>=b) return INF;
if(r<=b&&l>=a){
auto ite=sgt[now].upper_bound(II(b,0));
if(ite==sgt[now].begin()) return INF;
return prev(ite)->SEC;
}
int mid=(l+r)>>1;
return min(query(a,b,now<<1,l,mid),query(a,b,now<<1|1,mid,r));
}
int solve(int L,int R){
if(L>R) return 0;
int id=query(L,R+1);
if(id==INF) return 0;
return solve(L,l[id]-1)+solve(r[id]+1,R)+r[id]-l[id]+1;
}
int main(){
scanf("%d%d",&n,&m);
rb(i,1,m) scanf("%d%d",&l[i],&r[i]),seg[r[i]-l[i]+1].PB(i);
vector<int> ans;
rl(i,n,1){
for(auto it:seg[i]){
int now=l[it]+N-1;
while(now){
if(sgt[now].empty()){
sgt[now].insert(II(r[it],it));
}
else{
auto ite=sgt[now].lower_bound(II(r[it],0));
while(ite!=sgt[now].end()&&ite->SEC>it) ite=sgt[now].erase(ite);
if(ite!=sgt[now].begin()&&prev(ite)->SEC<it);
else if(ite!=sgt[now].end()&&ite->FIR==r[it]);
else sgt[now].insert(II(r[it],it));
}
now>>=1;
}
}
ans.PB(solve(1,n));
}
reverse(ALL(ans));
for(auto it:ans){
printf("%d\n",it);
}
return 0;
}