AtCoder Beginner Contest 441题解
D - Paid Walk
简单dfs
int n,m,s,l,t;
vector<int>ans;
vector<pii>g[N];
void dfs(int u,int cs,int st){
if(cs>t)return;
if(st==l){
if(cs>=s&&cs<=t)ans.push_back(u);
return;
}
for(auto [v,w]:g[u]){
dfs(v,cs+w,st+1);
}
}
void solve(){
cin>>n>>m>>l>>s>>t;
int u,v,w;
up(i,1,m){
cin>>u>>v>>w;
g[u].push_back({v,w});
}
dfs(1,0,0);
sort(ans.begin(),ans.end());
ans.erase(unique(ans.begin(),ans.end()),ans.end());
for(auto x:ans)cout<<x<<" ";
}
E - A > B substring
可以将其映射到一个二位平面上,遇到 A 视为 +1,B 视为 -1,固定 i 位左端点,找后面有多少个数比a[i]大,求固定区间一个数的排名,平衡树很容易被想到。
int n;
string s;
int a[N];
struct FHQTreap{
int cnt=0,root=0;
struct node{
int ls,rs;
int key,pri;
int siz;
}tr[N];
int ans;
inline void build(int x){
cnt++;
tr[cnt].siz=1;
tr[cnt].ls=tr[cnt].rs=0;
tr[cnt].key=x;
tr[cnt].pri=rand();
}
inline void push_up(int k){
tr[k].siz=tr[tr[k].ls].siz+tr[tr[k].rs].siz+1;
}
inline void split(int u,int x,int &l,int &r){
if(u==0){l=r=0;return;}
if(tr[u].key<=x){
l=u;
split(tr[u].rs,x,tr[u].rs,r);
}
else{
r=u;
split(tr[u].ls,x,l,tr[u].ls);
}
push_up(u);
}
inline int merge(int l,int r){
if(l==0||r==0)return l+r;
if(tr[l].pri>tr[r].pri){
tr[l].rs=merge(tr[l].rs,r);
push_up(l);
return l;
}
else{
tr[r].ls=merge(l,tr[r].ls);
push_up(r);
return r;
}
}
inline void insert(int x){
int l,r;
split(root,x,l,r);
build(x);
root=merge(merge(l,cnt),r);
}
inline void del(int x){
int l,r,p;
split(root,x,l,r);
split(l,x-1,l,p);
p=merge(tr[p].ls,tr[p].rs);
root=merge(merge(l,p),r);
}
inline int getrank(int x){
int l,r;
split(root,x-1,l,r);
int last=tr[l].siz+1;
root=merge(l,r);
return last;
}
inline int kth(int u,int k){
if(k==tr[tr[u].ls].siz+1)return u;
if(k<=tr[tr[u].ls].siz)return kth(tr[u].ls,k);
else return kth(tr[u].rs,k-tr[tr[u].ls].siz-1);
}
inline int getpre(int x){
int l,r;
split(root,x-1,l,r);
int last=tr[kth(l,tr[l].siz)].key;
root=merge(l,r);
return last;
}
inline int getpre1(int x){
int l,r;
split(root,x,l,r);
int last=tr[kth(l,tr[l].siz)].key;
root=merge(l,r);
return last;
}
inline int getnxt(int x){
int l,r;
split(root,x,l,r);
int last=tr[kth(r,1)].key;
root=merge(l,r);
return last;
}
inline int size(){
return tr[root].siz;
}
inline int getans(int x){
int a=getpre1(x),b=getnxt(x);
if(x-a>b-x)return b;
else return a;
}
}T;
void solve(){
cin>>n>>s;
s=" "+s;
up(i,1,n){
if(s[i]=='A')a[i]=a[i-1]+1;
if(s[i]=='B')a[i]=a[i-1]-1;
if(s[i]=='C')a[i]=a[i-1];
T.insert(a[i]);
}
int ans=0,pos=n;
up(i,1,n){
ans+=pos-T.getrank(a[i-1]+1)+1;
T.del(a[i]);
pos--;
}
cout<<ans;
}
F - Must Buy
一个经典的trick,分别求前缀和后缀就行了。
注意,二维背包和一维背包有一点区别,p[i]之前的要继承。
int n,m;
int f[1005][N],g[1005][N];
int p[1050],v[1050];
void solve(){
cin>>n>>m;
up(i,1,n){
cin>>p[i]>>v[i];
}
up(i,1,n){
dn(j,m,0){
f[i][j]=max(f[i][j],f[i-1][j]);
if(j>=p[i])f[i][j]=max(f[i-1][j-p[i]]+v[i],f[i][j]);
}
}
dn(i,n,1){
dn(j,m,0){
g[i][j]=max(g[i][j],g[i+1][j]);
if(j>=p[i])g[i][j]=max(g[i+1][j-p[i]]+v[i],g[i][j]);
}
}
int ans=f[n][m];
up(i,1,n){
int maxl=0,maxl2=0;
up(j,0,m){
maxl=max(maxl,f[i-1][j]+g[i+1][m-j]);
if(j>=p[i])maxl2=max(maxl2,v[i]+f[i-1][j-p[i]]+g[i+1][m-j]);
}
if(maxl2==ans&&maxl<ans)cout<<"A";
if(maxl2==ans&&maxl==ans)cout<<"B";
if(maxl==ans&&maxl2<ans)cout<<"C";
}
}

浙公网安备 33010602011771号