Atcoder AGC018 簡要題解
阿新 • • 發佈:2018-11-01
Coins
先轉化為一個點只有兩種屬性
,選出
個
,
個
的最大值。
如果固定選的集合那麼肯定要選 前 大的,我們列舉一下第 大的 是多大然後在兩邊貪心即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
const int N=1e5+50;
const LL INF=1e18;
int n,X,Y,Z;
LL ans=-INF,sum,pre[N],suf[N];
struct atom {LL x,y;}a[N];
priority_queue <LL> q;
int main() {
X=rd(), Y=rd(), Z=rd(), n=X+Y+Z;
for(int i=1;i<=n;i++) {
a[i].x=rd(), a[i].y=rd();
int c=rd(); sum+=c;
a[i].x-=c; a[i].y-=c;
a[i].x-=a[i].y;
}
sort(a+1,a+n+1,[](atom c,atom d) {return c.x>d.x;});
for(int i=1;i<=n;i++) {
pre[i]=pre[i-1]+a[i].x+a[i].y;
q.push(-(a[i].x+a[i].y));
if(q.size()>X) pre[i]+=q.top(), q.pop();
}
while(!q.empty()) q.pop();
for(int i=n;i>=1;i--) {
suf[i]=suf[i+1]+a[i].y;
q.push(-a[i].y);
if(q.size()>Y) suf[i]+=q.top(), q.pop();
}
for(int i=X;i+Y<=n;++i) ans=max(ans,pre[i]+suf[i+1]);
cout<<(ans+sum)<<'\n';
}
Tree and Hamilton Path
算出若每個邊獨立最多被計算多少次。
然後最優情況是這些和減去重心相鄰的某條邊。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair <int,int> pii;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
const int N=1e5+50;
int n,sze[N],mx_son[N],mx; LL ans;
vector <pii> edge[N];
inline void dfs(int x,int f) {
sze[x]=1;
for(auto v:edge[x])
if(v.first^f) {
dfs(v.first,x); sze[x]+=sze[v.first];
ans+=(LL)v.second*min(sze[v.first],n-sze[v.first])*2;
mx_son[x]=max(mx_son[x],sze[v.first]);
}
mx_son[x]=max(mx_son[x],n-sze[x]);
mx=min(mx,mx_son[x]);
}
int main() {
n=rd(); mx=n;
for(int i=1;i<n;i++) {
int x=rd(), y=rd(), v=rd();
edge[x].push_back(pii(y,v));
edge[y].push_back(pii(x,v));
}
dfs(1,0);
int mn=2e9;
if((!(n&1)) && mx==n/2) {
for(int i=1;i<=n;i++) if(mx_son[i]==n/2)
for(auto v:edge[i]) if(mx_son[v.first]==n/2) mn=min(mn,v.second);
} else {
for(int i=1;i<=n;i++) if(mx_son[i]==mx)
for(auto v:edge[i]) mn=min(mn,v.second);
}
ans-=mn;
cout<<ans<<'\n';
}
Sightseeing Plan
挺妙的,一條路徑的貢獻是與中間區域相交的塊的個數。
列舉入口,出口,然後是個二維組合數求和,可以 計算。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair <int,int> pii;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
const int N=1e7+50, mod=1e9+7;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+mod) : (x-y);}
inline int mul(int x,int y) {return (long long)x*y%mod;}
inline int power(int a,int b,int rs=1) {for(;b;b>>=1,a=mul(a,a)) if(b&1) rs=mul(rs,a); return rs;}
int X[7],Y[7],ans;
struct binom {
int fac[N],ifac[N];
binom() {
fac[0]=1;
for(int i=1;i<N;i++) fac[i]=mul(fac[i-1],i);
ifac[N-1]=power(fac[N-1],mod-2);
for(int i=N-2;~i;i--) ifac[i]=mul(ifac[i+1],i+1);
}
inline int C(int a,int b) {return mul(fac[a],mul(ifac[b],ifac[a-b]));}
} C;
inline int path0(int x,int y) {
int in=C.C(y-Y[1]+x-X[1]+2,y-Y[1]+1)-C.C(y-Y[1]+x-X[2]+1,y-Y[1]+1);
in=((LL)in-C.C(y-Y[2