AtCoder Beginner Contest 445题解

D - Reconstruct Chocolate

水题,不讲不讲。

int h,w,n;
pii ans[N];
struct node{
    int h,w,id;
}a[N],b[N];
bool cmp1(node u,node v){
    return u.w>v.w;
}
bool cmp2(node u,node v){
    return u.h>v.h;
}
void print(){
    up(i,1,n){
        cout<<ans[i].fi<<" "<<ans[i].se<<endl;
    }
}
void dfs(int x,int y,int ida,int idb){
    if(ida==n+1||idb==n+1){
        print();
        exit(0);
    }
    if(a[ida].w==w-y+1){
        int res=0;
        while(ida<=n){
            if(ans[a[ida].id].fi==0){
                ans[a[ida].id]={x+res,y};
                //cout<<ans[a[ida].id].fi<<" "<<ans[a[ida].id].se<<endl;
                res+=a[ida].h;
            }
            ida++;
            if(a[ida].w!=w-y+1)break;
        }
        dfs(x+res,y,ida,idb);
    }
    else{
        int res=0;
        while(idb<=n){
            if(ans[b[idb].id].fi==0){
                ans[b[idb].id]={x,y+res};
                res+=b[idb].w;
            }
            idb++;
            if(b[idb].h!=h-x+1)break;
        }
        dfs(x,y+res,ida,idb);
    }
}
void solve(){
    cin>>h>>w>>n;
    int u,v;
    up(i,1,n){
        cin>>u>>v;
        a[i]={u,v,i};
        b[i]={u,v,i};
    }
    sort(a+1,a+1+n,cmp1);
    sort(b+1,b+1+n,cmp2);
    dfs(1,1,1,1);
}

E - Many LCMs

这个题还是有点意思的。
核心是预处理出1e7范围内所有数最小的质因子。
然后对给出的2e5个数进行处理,记录每个出现的因子最大的次数和第二大的次数。

int n,a[N];
int bp[M+1];
vector<int>pri;
void init(){
    iota(bp, bp+M+1, 0);
    for (int x = 2; x <= M; x++){
        if (bp[x] == x) pri.push_back(x);
        for (auto p : pri) {
            if (p * x > M || p > bp[x]) break;
            bp[p * x] = p;
        }
    }
}
int ksm(int a,int b){
    int res=1;
    while(b){
        if(b&1)res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
void solve(){
    cin>>n;
    up(i,1,n){
        cin>>a[i];
    }
    map<int,int>e1,e2;
    up(i,1,n){
        int x=a[i];
        while(x>1){
            int p=bp[x],cnt=0;
            while(x%p==0){
                x/=p;
                cnt++;
            }   
            if(cnt>e1[p])e2[p]=e1[p],e1[p]=cnt;
            else if(cnt>e2[p])e2[p]=cnt;
        }
    }
    int lcm=1;
    for(auto [p,e]:e1)lcm=lcm*ksm(p,e)%mod;
    up(i,1,n){
        int x=a[i],ans=lcm;
        while(x>1){
            int p=bp[x],cnt=0;
            while(x%p==0){
                x/=p;cnt++;
            }   
            if(cnt==e1[p]){
                ans=ans*ksm(ksm(p,cnt-e2[p]),mod-2)%mod;
            }
        }
        cout<<ans<<" ";
    }
    cout<<endl;
}

F - Exactly K Steps 2

min-plus 矩阵乘法。
一个有趣的知识点。

#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>

int main() {
    using namespace std;
    unsigned N, K;
    cin >> N >> K;
    vector C(N, vector<unsigned long>(N));

    for (auto&& row : C)
        for (auto&& c : row)
            cin >> c;

    // Finds results of (a + b) moves, given results of a moves and b moves
    const auto prod{[N, inf{ranges::max(C | views::join) * K}](const auto& lhs, const auto& rhs) {
        // Initialize with a sufficiently large value
        vector ret(N, vector(N, inf));
        for (const auto i : views::iota(0U, N))
            for (const auto j : views::iota(0U, N))
                for (const auto k : views::iota(0U, N))
                    ret[i][k] = min(ret[i][k], lhs[i][j] + rhs[j][k]);
        return ret;
    }};

    auto ans(C);
    --K;

    // Fast exponentiation
    while (K) {
        if (K & 1)
            ans = prod(ans, C);
        C = prod(C, C);
        K /= 2;
    }

    for (const auto i : views::iota(0U, N))
        cout << ans[i][i] << endl;
    return 0;
}
posted @ 2026-03-10 15:25  LiQXing  阅读(2)  评论(0)    收藏  举报