ABC415 个人题解

A

略。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define uint unsigned long long
#define PII pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define SET(a,b) memset(a,b,sizeof(a))
#define CPY(a,b) memcpy(a,b,sizeof(b))
#define rep(i,j,k) for(int i=(j);i<=(k);++i)
#define per(i,j,k) for(int i=(j);i>=(k);--i)
int read() {
   int a=0, f=1; char c=getchar();
   while(!isdigit(c)) {
       if(c=='-') f=-1;
       c=getchar();
   }
   while(isdigit(c)) a=a*10+c-'0', c=getchar();
   return a*f;
}
int n, x, a[105];
signed main() {
    n=read();
    rep(i,1,n) ++a[read()];
    x=read();
    if(a[x]) puts("Yes"); else puts("No");
    return 0;
}

B

略。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define uint unsigned long long
#define PII pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define SET(a,b) memset(a,b,sizeof(a))
#define CPY(a,b) memcpy(a,b,sizeof(b))
#define rep(i,j,k) for(int i=(j);i<=(k);++i)
#define per(i,j,k) for(int i=(j);i>=(k);--i)
int read() {
   int a=0, f=1; char c=getchar();
   while(!isdigit(c)) {
       if(c=='-') f=-1;
       c=getchar();
   }
   while(isdigit(c)) a=a*10+c-'0', c=getchar();
   return a*f;
}
priority_queue<int,vector<int>,greater<int> > q;
string s;
signed main() {
    cin>>s;
    for(int i=0;i<s.size();i++) {
        if(s[i]=='#') q.push(i+1);
    }
    while(q.size()) {
        int x=q.top(); q.pop();
        int y=q.top(); q.pop();
        printf("%d,%d\n",x,y);
    }
    return 0;
}

C

把容器内元素的状况压成一个二进制数,危险状态 ban 掉,DFS判断是否存在一条从 $0$ 到 $2^n -1$ 的路径即可。

每个点最多连出 $n$ 条边,复杂度 $O(n 2^n)$。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define uint unsigned long long
#define PII pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define SET(a,b) memset(a,b,sizeof(a))
#define CPY(a,b) memcpy(a,b,sizeof(b))
#define rep(i,j,k) for(int i=(j);i<=(k);++i)
#define per(i,j,k) for(int i=(j);i>=(k);--i)
int read() {
   int a=0, f=1; char c=getchar();
   while(!isdigit(c)) {
       if(c=='-') f=-1;
       c=getchar();
   }
   while(isdigit(c)) a=a*10+c-'0', c=getchar();
   return a*f;
}
const int N=5e5+5;
int T, n, U, ans;
int ban[N], v[N];
vector<int> p[N];
string s;
void dfs(int S) {
    v[S]=1;
    if(S==U) {
        ans=1;
        return;
    }
    for(int i=0;i<n;i++) {
        int k=S|(1<<i);
        if(!ban[k]&&!v[k]&&i!=k) dfs(k);
    }
}
void solve() {
    n=read();
    cin>>s;
    U=(1<<n)-1;
    for(int i=0;i<=U;i++) ban[i]=v[i]=0, p[i].clear();
    for(int i=0;i<s.size();i++) {
        if(s[i]=='1') ban[i+1]=1;
    }
    ans=0;
    dfs(0);
    if(ans) puts("Yes"); else puts("No");
}
signed main() {
    T=read();
    while(T--) solve();
    return 0;
}

D

贪心策略:按照 $A_i – B_i$ 递增排序,尽可能选择满足 $n \ge A_i$ 的 $i$。

证明:由于无论选择哪个 $i$ 收益都是 $1$,所以选择补回来多的一定不劣。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define uint unsigned long long
#define PII pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define SET(a,b) memset(a,b,sizeof(a))
#define CPY(a,b) memcpy(a,b,sizeof(b))
#define rep(i,j,k) for(int i=(j);i<=(k);++i)
#define per(i,j,k) for(int i=(j);i>=(k);--i)
ll read() {
   ll a=0, f=1; char c=getchar();
   while(!isdigit(c)) {
       if(c=='-') f=-1;
       c=getchar();
   }
   while(isdigit(c)) a=a*10+c-'0', c=getchar();
   return a*f;
}
const int N=2e5+5;
int m;
ll n;
struct node {
    ll x, y;
} a[N];
bool operator<(const node& a,const node& b) {
    return (a.x-a.y)>(b.x-b.y);
}
ll cil(ll x,ll y) { return (x+y-1)/y; }
priority_queue<node> q;
signed main() {
    n=read(), m=read();
    rep(i,1,m) {
        a[i].x=read(), a[i].y=read();
        q.push(a[i]);
    }
    ll ans=0;
    while(q.size()&&n>0) {
        node t=q.top(); q.pop();
        if(n<t.x) continue;
        ll dlt=n-t.x;
        ll cnt=dlt/(t.x-t.y);
        ans+=cnt;
        n-=cnt*(t.x-t.y);
        if(n>=t.x) {
            n-=t.x-t.y;
            ans++;
        }
    }
    printf("%lld\n",ans);
    return 0;
}

E

设 $f(i,j)$ 为从 $(i,j)$ 到达 $(n,m)$ 至少需要多少钱。

$$
f(i,j) = \min \left\{ f(i+1,j),f(i,j+1) \right\} + p_{i+j-1} – a_{i,j}
$$

如果计算出的 $f(i,j)<0$,说明不需要额外花钱,直接置为 $0$ 即可。

为什么不能设 $f(i,j)$ 为从 $(1,1)$ 到达 $(i,j)$ 至少需要多少钱呢?

因为我们无法解决,到达 $(i,j)$ 后钱还有剩的情况,即存在后效性。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define uint unsigned long long
#define PII pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define eb emplace_back
#define ef emplace_front
#define SET(a,b) memset(a,b,sizeof(a))
#define CPY(a,b) memcpy(a,b,sizeof(b))
#define rep(i,j,k) for(int i=(j);i<=(k);++i)
#define per(i,j,k) for(int i=(j);i>=(k);--i)
int read() {
   int a=0, f=1; char c=getchar();
   while(!isdigit(c)) {
       if(c=='-') f=-1;
       c=getchar();
   }
   while(isdigit(c)) a=a*10+c-'0', c=getchar();
   return a*f;
}
int n, m, p[500000];
signed main() {
    n=read(), m=read();
    vector a(n+5,vector<int>(m+5));
    rep(i,1,n) rep(j,1,m) a[i][j]=read();
    rep(i,1,n+m-1) p[i]=read();
    vector f(n+5,vector<ll>(m+5,1e18));
    f[n][m]=0;
    per(i,n,1) per(j,m,1) {
        if(i+1<=n) f[i][j]=min(f[i][j],f[i+1][j]);
        if(j+1<=m) f[i][j]=min(f[i][j],f[i][j+1]);
        f[i][j]+=p[i+j-1]-a[i][j];
        f[i][j]=max(f[i][j],0ll);
    }
    printf("%lld\n",f[1][1]);
    return 0;
}

F

线段树板子题。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define uint unsigned long long
#define PII pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define eb emplace_back
#define ef emplace_front
#define SET(a,b) memset(a,b,sizeof(a))
#define CPY(a,b) memcpy(a,b,sizeof(b))
#define rep(i,j,k) for(int i=(j);i<=(k);++i)
#define per(i,j,k) for(int i=(j);i>=(k);--i)
int read() {
   int a=0, f=1; char c=getchar();
   while(!isdigit(c)) {
       if(c=='-') f=-1;
       c=getchar();
   }
   while(isdigit(c)) a=a*10+c-'0', c=getchar();
   return a*f;
}
const int N=5e5+5;
int n, q;
string s;
struct node {
    int w, lt, rt, lw, rw, len;
    node() { w=lt=rt=lw=rw=len=0; }
    node(int a,int b,int c,int d,int e,int g) {
        w=a, lt=b, rt=c, lw=d, rw=e, len=g;
    }
};
node operator+(const node& a,const node& b) {
    node c=node(0,0,0,0,0,0);
    c.w=max(a.w,b.w);
    if(a.rw==b.lw) c.w=max(c.w,a.rt+b.lt);
    c.lw=a.lw, c.rw=b.rw;
    c.lt=a.lt, c.rt=b.rt;
    if(a.lw==a.rw&&a.len==a.lt&&a.rw==b.lw) c.lt=max(c.lt,a.lt+b.lt);
    if(b.lw==b.rw&&b.len==b.rt&&a.rw==b.lw) c.rt=max(c.rt,b.rt+a.rt);
    c.len=a.len+b.len;
    return c;
}
namespace seg {
    node t[N<<2];
    void pushup(int x) {
        t[x]=t[x<<1]+t[x<<1|1];
    }
    void build(int x=1,int l=1,int r=n) {
        if(l==r) {
            t[x]=node(1,1,1,s[l-1]-'a',s[l-1]-'a',1);
            return;
        }
        int mid=(l+r)>>1;
        build(x<<1,l,mid);
        build(x<<1|1,mid+1,r);
        pushup(x);
    }
    void upd(int p,int k,int x=1,int l=1,int r=n) {
        if(l==r) {
            t[x]=node(1,1,1,k,k,1);
            return;
        }
        int mid=(l+r)>>1;
        if(p<=mid) upd(p,k,x<<1,l,mid);
        else upd(p,k,x<<1|1,mid+1,r);
        pushup(x);
    }
    node query(int L,int R,int x=1,int l=1,int r=n) {
        // printf("%d %d\n",l,r);
        if(L<=l&&r<=R) return t[x];
        int mid=(l+r)>>1;
        node res1, res2;
        if(L<=mid) res1=query(L,R,x<<1,l,mid);
        if(R>mid) res2=query(L,R,x<<1|1,mid+1,r);
        if(res1.w&&!res2.w) return res1;
        if(!res1.w&&res2.w) return res2;
        if(res1.w&&res2.w) return res1+res2;
        return res1;
    }
};
signed main() {
    n=read(), q=read();
    cin>>s;
    seg::build();
    while(q--) {
        int op=read();
        if(op==1) {
            string c;
            int x=read();
            cin>>c;
            seg::upd(x,c[0]-'a');
        } else {
            int l=read(), r=read();
            node ans=seg::query(l,r);
            printf("%d\n",ans.w);
        }
    }
    return 0;
}

G

D 的加强版。

$A_i,B_i$ 数量很多,但值域很小,于是按照值域缩一下数量,保留每个$A_i$ 最大的 $B_j$ 即可。

不难发现,对于一个操作 $(A_i,B_i)$,其代价为 $A_i-B_i$,收益为 $B_i$,前提是 $n’ \ge A_i$。

设 $f_n$ 为当前有 $n$ 瓶可乐时能够额外产生的最大收益,这就是一个有限制的完全背包。

但是这样不能处理较大规模的数据。

我们断言:在 $n$ 较大时,不存在上述前提的限制,所以操作的顺序是无所谓的。

所以说我们可以把某一种操作放在前面连续进行多次。

操作数量很少,枚举即可,那么答案就是

$$
\max_{j=lim_0}^{lim_1} \Big \{ f_j + \lfloor \frac{n-j} {A_i-B_i} \rfloor \times B_i \Big \}
$$

复杂度取决于 $lim_0$ 和 $lim_1$ 的选取。

对于下界 $lim_0$,我们至少要留出来一个其他 $A_i$,所以令 $lim_0 = \max_{i=1}^m {A_i}$ 即可。

对于上界 $lim_1$,可以取 $lim_1(lim_1+1)$。

证明是不会的。没啥人做这题,日文翻译后也看不明白。

使用した $i’$ 以外のアイテムに対する $D_i$​ の総和が $K(K+1)$ 以上だと仮定する。

まず、操作の過程において $x$ が最初に K 以上になったタイミングについて考える。最初の $x$ を $K$ より大きくするメリットはないので、このときの $x$ は $K$ 以上 $2K$ 未満と仮定してよく、これ以降の操作について ​$x \ge B_i$ という条件を気にする必要はない。

仮定より、これ以降に使用した i′ 以外のアイテムに対する $D_i$ の総和は $K(K+1)−(2K−1)=K(K−1)+1$ 以上であり、特に使用した個数は $K$ 以上である。これらのアイテムのうち最初の $j$ 個に対するDi​ の総和を $S_j​ (0≤j≤K)$ とおく。鳩の巣原理より、$S_l​ \equiv S_r​ (\bmod D_{i’}​)$ なる $0≤l<r≤K$ が存在する。$l+1,l+2,…,r$ 個目のアイテムを使用する代わりに、アイテム $i$ を $\frac{S_r-S_l}{D_{i’}​​}$ 個使用することにして損しない。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define uint unsigned long long
#define PII pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define eb emplace_back
#define ef emplace_front
#define SET(a,b) memset(a,b,sizeof(a))
#define CPY(a,b) memcpy(a,b,sizeof(b))
#define rep(i,j,k) for(int i=(j);i<=(k);++i)
#define per(i,j,k) for(int i=(j);i>=(k);--i)
ll read() {
   ll a=0, f=1; char c=getchar();
   while(!isdigit(c)) {
       if(c=='-') f=-1;
       c=getchar();
   }
   while(isdigit(c)) a=a*10+c-'0', c=getchar();
   return a*f;
}
const int N=305;
ll n, f[N*N];
int m, mx[N], lim, mxa;
vector<PII > v;
signed main() {
    n=read(), m=read();
    rep(i,1,m) {
        int a=read(), b=read();
        lim=max(lim,a*(a+1));
        mx[a]=max(mx[a],b);
        mxa=max(mxa,a);
    }
    rep(i,1,300) if(mx[i]) {
        v.eb(MP(i-mx[i],mx[i]));
    }
    for(auto [x,y]:v) rep(i,x,lim) {
        if(i-x>=y) f[i]=max(f[i],f[i-x]+y);
    }
    ll ans=0;
    if(n<=lim) {
        rep(i,1,n) ans=max(ans,f[i]);
        printf("%lld\n",n+ans);
        exit(0);
    }
    for(auto [x,y]:v) {
        rep(j,mxa,lim) ans=max(ans,f[j]+(n-j)/x*y);
    }
    printf("%lld\n",n+ans);
    return 0;
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇