首页 > 其他分享 >The 2024 International Collegiate Programming Contest in Hubei Province, China

The 2024 International Collegiate Programming Contest in Hubei Province, China

时间:2024-05-16 17:07:40浏览次数:30  
标签:Province std CI Contest int auto Programming include define

Preface

感觉好久没训练了,这周末又要出战西安,只好找个平时的晚上抽空训练一场

这场题本身质量还是不错的,但由于徐神被模拟题关了一整场,我前期被一个分类讨论写的心态爆炸

导致最后一个medium的计数题没做出来,然后一个medium~hard的D题转化和性质基本都挖掘完了,最后没想到暴力增量法维护贡献(不过本来也没机时写了)


A. Long Live

签到,不难发现令\(a=1\)一定最优

#include <bits/stdc++.h>

int main() {
    std::ios::sync_with_stdio(false);
    int T; std::cin >> T;
    while(T--) {
        int64_t x, y;
        std::cin >> x >> y;
        std::cout << "1 " << x * y / (std::__gcd(x, y) * std::__gcd(x, y)) << char(10);
    }
    return 0;
}

B. Nana Likes Polygons

签到,不难发现面积最小的凸包一定是三角形,直接\(O(n^3)\)枚举顶点即可

#include<bits/stdc++.h>
using namespace std;

const int N = 105;
const int INF = (int)1e9+5;

int t, n;
struct Pt{
    int x, y;
    Pt operator-(Pt b)const{return Pt{x-b.x, y-b.y};}
    int crs(Pt b){return x*b.y-y*b.x;}
}pt[N];
int tcross(Pt a, Pt b, Pt c){return abs((b-a).crs(c-a));}


signed main(){
    ios::sync_with_stdio(0); cin.tie(0);
    cin >> t;
    while (t--){
        cin >> n;
        int ans = INF;
        for (int i=1; i<=n; ++i) cin >> pt[i].x >> pt[i].y;
        for (int i=1; i<=n; ++i) for (int j=i+1; j<=n; ++j) for (int k=j; k<=n; ++k){
            int res = tcross(pt[i], pt[j], pt[k]);
            if (res>0) ans = min(ans, res);
        }
        if (ans<INF) cout << ans*0.5L << '\n';
        else cout << "-1\n";
    }
    return 0;
}

C. Lili Likes Polygons

看起来是个很神秘的Flow题,没时间补了先弃疗


D. MACARON Likes Happy Endings

纯纯的套路题,首先这种分割成若干段的状态肯定是\(f_{i,j}\),表示把前\(i\)个数分成\(j\)段,且钦定\(i\)为某段的末尾的最小代价

转移的话就是枚举转移点\(k\),则有:\(f_{i,j}=\min_\limits{1\le k\le i} f_{k-1,j-1}+w(k,i)\),其中\(w(l,r)\)就是区间\([l,r]\)的sadness

然后祁神在比赛中证出了这个DP是有决策单调性的,即先固定\(j\)后,每个位置的最优决策点单调不减

赛中就一直在思考怎么快速维护\(w(l,r)\)的值,后面也想到了增量法但没想到直接暴力上复杂度就是对的

考虑类似莫队的处理,我们维护某个区间的端点\([l,r]\)以及贡献\(w(l,r)\),端点移动时贡献的变化量可以用桶来快速维护

最后在外面套一个经典的整体二分维护决策单调性的壳即可,对于两个端点单独分析移动次数后不难发现这部分的复杂度是正确的

总复杂度\(O(nk\log n)\)

#include<cstdio>
#include<iostream>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
const int N=100005,S=2e6+5,INF=1e18;
int n,k,d,x,pfx[N],f[N],g[N],bkt[S],L,R,ret;
inline void move(CI l,CI r)
{
	while (L>l) ++bkt[pfx[--L]],ret+=bkt[pfx[L-1]^d];
	while (L<l) ret-=bkt[pfx[L-1]^d],--bkt[pfx[L++]];
	while (R<r)
	{
		ret+=bkt[pfx[R+1]^d];
		if ((pfx[R+1]^pfx[L-1])==d) ++ret;
		++bkt[pfx[++R]];
	}
	while (R>r)
	{
		--bkt[pfx[R--]];
		if ((pfx[R+1]^pfx[L-1])==d) --ret;
		ret-=bkt[pfx[R+1]^d];
	}
}
inline void solve(CI pl,CI pr,CI l,CI r)
{
	if (l>r) return; int mid=l+r>>1,pos=-1;
	for (RI i=pl;i<=min(pr,mid);++i)
	{
		move(i,mid); int tmp=ret+g[i-1];
		if (tmp<f[mid]) f[mid]=tmp,pos=i;
	}
	solve(pl,pos,l,mid-1); solve(pos,pr,mid+1,r);
}
signed main()
{
	RI i,j; for (scanf("%lld%lld%lld",&n,&k,&d),i=1;i<=n;++i)
	scanf("%lld",&x),pfx[i]=pfx[i-1]^x; L=1; R=0; ret=0;
	/*static int cnt[S]; for (i=1;i<=n;++i) for (j=i;j<=n;++j)
	{
		move(i,j); ++cnt[pfx[i-1]]; int tmp=0;
		for (RI k=i;k<=j;++k) tmp+=cnt[pfx[k]^d],++cnt[pfx[k]];
		for (RI k=i;k<=j;++k) cnt[pfx[k]]=0; cnt[pfx[i-1]]=0;
		if (ret!=tmp) printf("[%lld,%lld] %lld %lld\n",i,j,ret,tmp);
	}*/
	for (i=1;i<=n;++i) move(1,i),f[i]=g[i]=ret;
	for (j=2;j<=k;++j)
	{
		for (i=1;i<=n;++i) f[i]=INF;
		for (solve(1,n,1,n),i=1;i<=n;++i) g[i]=f[i];
	}
	return printf("%lld",f[n]),0;
}

E. Spicy or Grilled?

签到,就我个人而言肯定是板烧大于麦辣的说

#include<cstdio>
#include<iostream>
using namespace std;
int t,n,x,a,b;
int main()
{
    for (scanf("%d",&t);t;--t)
    scanf("%d%d%d%d",&n,&x,&a,&b),printf("%d\n",x*b+(n-x)*a);
    return 0;
}

F. Enchanted

诈骗题,看到\(q\le 30\)后就知道是个一眼题了,但由于被祁神骗了以为有强制在线,就没去写离线建树的写法,最后又被卡空间又被卡时间搞到结束前5min才卡过去

不难发现我们把每个数看作\(2^{a_i}\)后,只要求一个区间和那么前两个询问操作都可以暴力求解了

剩下的单点修改和回退版本,可离线的话就是把转移的树状图建出来然后DFS并回溯即可

在线的做法就直接上主席树就完了,也没啥技巧,两种做法的时间复杂度都是一个\(\log\)的

#include<cstdio>
#include<iostream>
#define int long long
#define RI register int
using namespace std;
const int N=1e6+5,mod=1e9+7;
int n,m,A,p,q,a[N],opt,l,r,k; signed rt[N];
inline int rnd(void)
{
    return A=(7LL*A+13LL)%19260817;
}
class Segment_Tree
{
    public:
        struct segment
        {
            signed ls,rs;
            int sum;
        }O[N*50]; int idx;
    public:
        #define TN signed l=1,signed r=n
        #define LS l,mid
        #define RS mid+1,r
        inline void modify(signed lst,signed& now,signed pos,int mv,TN)
        {
            O[now=++idx]=O[lst]; if (l==r) return (void)(O[now].sum=mv); signed mid=l+r>>1;
            if (pos<=mid) modify(O[lst].ls,O[now].ls,pos,mv,LS); else modify(O[lst].rs,O[now].rs,pos,mv,RS);
            O[now].sum=O[O[now].ls].sum+O[O[now].rs].sum;
        }
        inline int query(signed now,signed beg,signed end,TN)
        {
            if (!now) return 0LL; if (beg<=l&&r<=end) return O[now].sum; signed mid=l+r>>1; int ret=0;
            if (beg<=mid) ret+=query(O[now].ls,beg,end,LS); if (end>mid) ret+=query(O[now].rs,beg,end,RS); return ret;
        }
        #undef TN
        #undef LS
        #undef RS
}SEG;
signed main()
{
    //std::cout << sizeof(SEG.O) / 1024.L / 1024.L << char(10);
    RI i,j; scanf("%lld%lld%lld%lld%lld",&n,&m,&A,&p,&q);
    for (i=1;i<=n;++i) a[i]=rnd()%q+1,SEG.modify(rt[0],rt[0],signed(i),1LL<<a[i]);
    //for (i=1;i<=n;++i) printf("%lld%c",a[i]," \n"[i==n]);
    for (i=1;i<=m;++i)
    {
        opt=rnd()%p+1;
        if (opt==1)
        {
            rt[i]=rt[i-1]; l=rnd()%n+1; r=rnd()%n+1;
            if (l>r) swap(l,r);
            int sum=SEG.query(rt[i],l,r),hb=0;
            //printf("sum=%lld\n", sum);
            for (j=60;j>=0;--j) if ((sum>>j)&1) { hb=j; break; }
            printf("%lld\n",hb);
        } else if (opt==2)
        {
            rt[i]=rt[i-1]; l=rnd()%n+1; r=rnd()%n+1; k=rnd()%q+1;
            if (l>r) swap(l,r);
            int sum=SEG.query(rt[i],l,r),ans=0;
            //printf("sum=%lld k=%lld\n", sum,k);
            for (j=k;j<=60;++j)
            {
                if ((sum>>j)&1) (ans+=(1LL<<(j+1)))%=mod; else break;
            }
            printf("%lld\n",ans);
        } else if (opt==3)
        {
            l=rnd()%n+1; k=rnd()%q+1;
            SEG.modify(rt[i-1],rt[i],l,(1LL<<k));
        } else rt[i]=rt[rnd()%i];
    }
    return 0;
}

G. Genshin Impact Startup Forbidden II

唉原神,唉围棋,据说就是个大力模拟题

但徐神写了三个version的代码,一个TLE飞了,一个过不了样例,最后修修补补终于淦过了这个题

由于我连围棋的规则都不知道所以就没碰这个题了QWQ

#include <bits/stdc++.h>

struct Stone { int id = 0, side = 0; };

Stone go[19][19];

int fa[500005], qi[500005];
std::vector<std::pair<int, int>> s[500005];
inline int father(int a) {
    if(a == fa[a]) return a;
    return fa[a] = father(fa[a]);
}

inline void unionn(int a, int b) {
    a = father(a), b = father(b);
    if(a == b) return ;
    if(s[a].size() > s[b].size()) std::swap(a, b);
    fa[a] = b; qi[b] += qi[a];
    for(auto a: s[a]) s[b].push_back(a);
    s[a].clear();
};

inline std::vector<std::pair<int, int>> nb(int x, int y) {
    constexpr int D[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    auto res = std::vector<std::pair<int, int>> {};
    res.reserve(4);
    for(auto &[dx, dy]: D) {
        int nx = x + dx, ny = y + dy;
        if(0 <= nx && nx < 19 && 0 <= ny && ny < 19) res.emplace_back(nx, ny);
    }
    return res;
}

inline int& get_qi(int x, int y) { return qi[father(go[x][y].id)]; }
inline int side(int x, int y) { return go[x][y].side; }

int remove(int i) {
    for(auto [x, y]: s[i]) {
        for(auto [nx, ny]: nb(x, y)) if(side(nx, ny))
            get_qi(nx, ny) += 1;
        go[x][y] = {0, 0};
    }
    return s[i].size();
}

int remove(int x, int y) { return remove(father(go[x][y].id)); }

auto main() -> int {
    std::ios::sync_with_stdio(false);
    int m, player = 1;
    std::cin >> m;
    for(int i = 1; i <= m; ++i) fa[i] = i;
    for(int i = 1; i <= m; ++i, player = -player) {
        int x, y; std::cin >> x >> y;
        x -= 1; y -= 1;
        s[i].emplace_back(x, y);

        int ans1 = 0, ans2 = 0;
        go[x][y] = { .id = i, .side = player };

        auto NB = nb(x, y);

        for(auto [nx, ny]: NB) if(side(nx, ny)) get_qi(nx, ny) -= 1;
        for(auto [nx, ny]: NB) if(side(nx, ny) == -player && get_qi(nx, ny) == 0) ans1 += remove(nx, ny);
        qi[i] = 0;
        for(auto [nx, ny]: NB) if(side(nx, ny) == 0) qi[i] += 1;
        for(auto [nx, ny]: NB) if(side(nx, ny) == player) unionn(i, go[nx][ny].id);
        if(get_qi(x, y) == 0) ans2 = remove(x, y);

        if(player > 0) std::swap(ans1, ans2);
        std::cout << ans1 << ' ' << ans2 << char(10);

        // for(int i = 0; i < 5; ++i) for(int j = 0; j < 5; ++j) {
        //     switch(go[i][j].side) {
        //         case 1: std::cout << qi[father(go[i][j].id)]; break;
        //         case -1: std::cout << 'X'; break;
        //         case 0: std::cout << '_';
        //     }
        //     if(j == 4) std::cout << "\n";
        // }
        // std::cout <<"----------\n";
    }
    return 0;
}

H. Genshin Impact Startup Forbidden III

很套路的题,由于有鱼的格子数量只有\(\le 10\)个,然后这些格子里鱼的数量\(\in\{0,1,2,3\}\),因此直接状压状态数就是\(4^{10}\)可以接受

然后就是写个大力BFS找到从初始状态到全\(0\)的最短路即可,注意最近CF机子慢的离谱,需要加上各种奇妙优化才能通过

#include<cstdio>
#include<iostream>
#include<vector>
#include<map>
#include<queue>
#include<utility>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
typedef pair <int,int> pi;
const int N=15,S=(1<<20)+5,dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
int n,m,k,x[N],y[N],z[N],dist[S]; map <pi,vector <int>> rst; vector <vector <int>> state;
int main()
{
    RI i,j; scanf("%d%d%d",&n,&m,&k); vector <int> st;
    for (i=0;i<k;++i) scanf("%d%d%d",&x[i],&y[i],&z[i]),st.push_back(z[i]);
    for (i=0;i<k;++i)
    {
        rst[pi(x[i],y[i])].push_back(i);
        for (j=0;j<4;++j)
        {
            int nx=x[i]+dx[j],ny=y[i]+dy[j];
            if (nx<1||nx>n||ny<1||ny>m) continue;
            rst[pi(nx,ny)].push_back(i);
        }
    }
    for (auto [it,vec]:rst) state.push_back(vec);
    auto H=[&](vector <int>& vec)
    {
        int v=0; for (auto x:vec) v=v*4+x; return v;
    };
    memset(dist,-1,sizeof(dist));
    queue <vector <int>> q; q.push(st); dist[H(st)]=0;
    while (!q.empty())
    {
        auto cur=q.front(); q.pop(); int hc=H(cur);
        for (auto &vec:state)
        {
            auto nxt=cur;
            for (auto &x:vec) if (nxt[x]>0) --nxt[x];
            int hn=H(nxt); if (~dist[hn]) continue;
            dist[hn]=dist[hc]+1; q.push(nxt);
        }
    }
    return printf("%d",dist[0]),0;
}

I. Colorful Tree

套路题,话说怎么又是动态维护直径,几天后的武汉邀请赛也有一个直径题,难道是去年杭州站带起的风向?

首先注意到一个点变黑之后就永远不会变回来了,因此我们可以对每个点维护出它第一次变黑的时间

具体方法就是把染色操作倒着考虑,每次用树剖+线段树实现区间赋值操作,修改的值就是当前操作的编号,最后每个点的点权就是所求的时间\(a_i\),同理\(a_i-1\)​就是每个点最后保持白色的时间

定义一条边\((x,y)\)变黑的时间为\(\max(a_x,a_y)\),同理倒过来做时它变白的时间为\(\min(a_x-1,a_y-1)\)

首先考虑黑色节点构成的森林,不难发现我们只需要按照时序将每条边加入,用并查集维护连通块内的直径端点即可

白色节点构成的森林同理,直接倒过来做一遍即可,总复杂度\(O(n\log n)\)

#include<cstdio>
#include<iostream>
#include<vector>
#include<utility>
#define RI register int
#define CI const int&
using namespace std;
typedef pair <int,int> pi;
const int N=200005;
int t,n,q,x[N],y[N],u[N],v[N],ans[N],fa[N],ret;
vector <int> E[N]; vector <pi> B[N],W[N];
class Segment_Tree
{
    private:
        int val[N<<2],tag[N<<2];
        inline void apply(CI now,CI mv)
        {
            val[now]=tag[now]=mv;
        }
        inline void pushdown(CI now)
        {
            if (tag[now]) apply(now<<1,tag[now]),apply(now<<1|1,tag[now]),tag[now]=0;
        }
    public:
        #define TN CI now=1,CI l=1,CI r=N
        #define LS now<<1,l,mid
        #define RS now<<1|1,mid+1,r
        inline void build(TN)
        {
            val[now]=q+1; tag[now]=0; if (l==r) return;
            int mid=l+r>>1; build(LS); build(RS);
        }
        inline void modify(CI beg,CI end,CI mv,TN)
        {
            if (beg<=l&&r<=end) return apply(now,mv); int mid=l+r>>1; pushdown(now);
            if (beg<=mid) modify(beg,end,mv,LS); if (end>mid) modify(beg,end,mv,RS);
        }
        inline int query(CI pos,TN)
        {
            if (l==r) return val[now]; int mid=l+r>>1; pushdown(now);
            if (pos<=mid) return query(pos,LS); else return query(pos,RS);
        }
        #undef TN
        #undef LS
        #undef RS
}SEG;
namespace Heavy_Division
{
    int idx,top[N],dep[N],sz[N],dfn[N],anc[N],son[N];
    inline void DFS1(CI now=1,CI fa=0)
    {
        sz[now]=1; dep[now]=dep[fa]+1; anc[now]=fa; son[now]=0;
        for (auto to:E[now]) if (to!=fa)
        {
            DFS1(to,now); sz[now]+=sz[to];
            if (sz[to]>sz[son[now]]) son[now]=to;
        }
    }
    inline void DFS2(CI now=1,CI tf=1)
    {
        dfn[now]=++idx; top[now]=tf;
        if (son[now]) DFS2(son[now],tf);
        for (int to:E[now]) if (to!=anc[now]&&to!=son[now]) DFS2(to,to);
    }
    inline void modify(int x,int y,CI mv)
    {
        while (top[x]!=top[y])
        {
            if (dep[top[x]]<dep[top[y]]) swap(x,y);
            SEG.modify(dfn[top[x]],dfn[x],mv);
            x=anc[top[x]];
        }
        if (dep[x]<dep[y]) swap(x,y);
        SEG.modify(dfn[y],dfn[x],mv);
    }
    inline int LCA(int x,int y)
    {
        while (top[x]!=top[y])
        {
            if (dep[top[x]]<dep[top[y]]) swap(x,y);
            x=anc[top[x]];
        }
        if (dep[x]<dep[y]) swap(x,y);
        return y;
    }
};
using namespace Heavy_Division;
inline int getfa(CI x)
{
    return x!=fa[x]?fa[x]=getfa(fa[x]):x;
}
inline int calc(CI x,CI y)
{
    return dep[x]+dep[y]-dep[LCA(x,y)]*2;
}
inline void merge(int x,int y)
{
    x=getfa(x); y=getfa(y); fa[y]=x;
    int ux=u[x],vx=v[x],uy=u[y],vy=v[y];
    if (calc(uy,vy)>calc(u[x],v[x])) u[x]=uy,v[x]=vy;
    if (calc(ux,uy)>calc(u[x],v[x])) u[x]=ux,v[x]=uy;
    if (calc(ux,vy)>calc(u[x],v[x])) u[x]=ux,v[x]=vy;
    if (calc(vx,uy)>calc(u[x],v[x])) u[x]=vx,v[x]=uy;
    if (calc(vx,vy)>calc(u[x],v[x])) u[x]=vx,v[x]=vy;
    ret=max(ret,calc(u[x],v[x]));
}
int main()
{
    for (scanf("%d",&t);t;--t)
    {
        RI i; for (scanf("%d%d",&n,&q),i=1;i<n;++i)
        scanf("%d%d",&x[i],&y[i]),E[x[i]].push_back(y[i]),E[y[i]].push_back(x[i]);
        for (DFS1(),DFS2(),i=1;i<=q;++i) scanf("%d%d",&u[i],&v[i]);
        for (SEG.build(),i=q;i>=1;--i) modify(u[i],v[i],i);
        //for (i=1;i<=n;++i) printf("%d%c",SEG.query(dfn[i])," \n"[i==n]);
        for (i=1;i<n;++i)
        {
            int X=SEG.query(dfn[x[i]]),Y=SEG.query(dfn[y[i]]);
            int b=max(X,Y),w=min(X,Y)-1;
            if (1<=b&&b<=q) B[b].push_back(pi(x[i],y[i]));
            if (1<=w&&w<=q) W[w].push_back(pi(x[i],y[i]));
        }
        for (ret=0,i=1;i<=n;++i) fa[i]=u[i]=v[i]=i;
        for (i=1;i<=q;++i)
        {
            for (auto [x,y]:B[i]) merge(x,y);
            ans[i]=ret;
        }
        for (ret=0,i=1;i<=n;++i) fa[i]=u[i]=v[i]=i;
        for (i=q;i>=1;--i)
        {
            for (auto [x,y]:W[i]) merge(x,y);
            ans[i]=max(ans[i],ret);
        }
        for (i=1;i<=q;++i) printf("%d\n",ans[i]+1);
        for (idx=0,i=1;i<=n;++i) E[i].clear();
        for (i=1;i<=q;++i) B[i].clear(),W[i].clear(),ans[i]=0;
    }
}

J. Points on the Number Axis A

签到题,手玩一下就会发现答案为\(\frac{\sum_{i=1}^n x_i}{n}\)

#include<bits/stdc++.h>
using namespace std;
#define int long long

const int MOD = 998244353;
int powe(int x, int p){
    int res=1;
    while (p>0){if (p&1) res=res*x%MOD; x=x*x%MOD; p>>=1;}
    return res;
}


signed main(){
    ios::sync_with_stdio(0); cin.tie(0);
    int n; cin >> n;
    int sum=0;
    for (int i=1; i<=n; ++i){
        int a; cin >> a;
        sum = (sum+a)%MOD;
    }
    cout << sum*powe(n, MOD-2)%MOD << '\n';
    return 0;
}

K. Points on the Number Axis B

刚开始读错J的题以为只能合并相邻两个,结果后面发现原来就是K题的意思,有点没绷住

徐神后面给了个神秘的生成函数做法,但由于数据范围估计跑不过以及机时问题就没写了,后面看了下题解好像挺傻逼的一个题

给题解中不清楚的地方补充一下,首先一个自然的想法就是设\(f_{n,m}\)表示当剩下\(n\)个数时,从左到右第\(m\)个数最后对答案的贡献系数

不难发现这个定义和题解中的类似,只需要变换下标就能相互转化,不过题解中的状态最后得到的式子相对比较简介,就以之为准

然后我们求出\(g_{i,j}\)的递推式后,可以直接大力猜测\(g_{i,j}=\prod(i-\frac{1}{2})(j-\frac{1}{2})\times C_{i+j}^i\),具体证明带进去化简一下就可以发现是成立的

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=2e6+5,mod=998244353,inv2=(mod+1)/2;
int n,ans,fact[N],ifac[N],prod[N];
inline int quick_pow(int x,int p=mod-2,int mul=1)
{
	for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
inline void init(CI n)
{
	RI i; for (fact[0]=i=1;i<=n;++i) fact[i]=1LL*fact[i-1]*i%mod;
	for (ifac[n]=quick_pow(fact[n]),i=n-1;i>=0;--i) ifac[i]=1LL*ifac[i+1]*(i+1)%mod;
	for (prod[0]=i=1;i<=n;++i) prod[i]=1LL*prod[i-1]*(i-inv2+mod)%mod;
}
inline int C(CI n,CI m)
{
	if (n<0||m<0||n<m) return 0;
	return 1LL*fact[n]*ifac[m]%mod*ifac[n-m]%mod;
}
int main()
{
	RI i; for (scanf("%d",&n),init(2*n),i=1;i<=n;++i)
	{
		int x=i-1,y=n-i,p; scanf("%d",&p);
		(ans+=1LL*C(x+y,x)*prod[x]%mod*prod[y]%mod*ifac[x+y]%mod*p%mod)%=mod;
	}
	return printf("%d",ans),0;
}

L. LCMs

分类讨论题,刚开始漏了种Case卡了好久,后面过了其它几个题后回头来看才发现问题所在

首先特判一些Corner Case:

  • 当\(a=b\)时,输出\(0\)
  • 当\(a\mid b\)时,输出\(b\)
  • 当\(\gcd(a,b)>1\)时,输出\(a+b\)

否则仅考虑\(a,b\)互质的情况,不妨设\(a\)的最小质因子为\(p\),\(b\)的最小质因子为\(q\),同时结合样例我们知道\(2\)是一个很有用的中介点

直接在\(a,b,p,q,2\)这五个点间跑一个\(a\to b\)的最短路即可,当然具体实现时可以直接讨论走法,但还是很容易遗漏的说

#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
int t,a,b;
signed main()
{
    for (scanf("%lld",&t);t;--t)
    {
        auto lcm=[&](CI x,CI y)
        {
            return x/__gcd(x,y)*y;
        };
        scanf("%lld%lld",&a,&b); int ans=lcm(a,b);
        if (a==b) ans=min(ans,0LL);
        if (b%a==0) ans=min(ans,b);
        if (__gcd(a,b)!=1) ans=min(ans,a+b);
        auto resolve=[&](CI n)
        {
            for (RI i=2;i*i<=n;++i) if (n%i==0) return i;
            return n;
        };
        int p=resolve(a),q=resolve(b);
        ans=min(ans,lcm(a,p)+lcm(p,b));
        ans=min(ans,lcm(a,q)+lcm(q,b));
        ans=min(ans,lcm(a,2)+lcm(2,b));
        ans=min(ans,lcm(a,p)+lcm(p,2)+lcm(2,b));
        ans=min(ans,lcm(a,2)+lcm(2,q)+lcm(q,b));
        ans=min(ans,lcm(a,p)+lcm(p,q)+lcm(q,b));
        ans=min(ans,lcm(a,p)+lcm(p,2)+lcm(2,q)+lcm(q,b));
        printf("%lld\n",ans);
    }
    return 0;
}

Postscript

这周继续出征西安,打完这场后这学期剩下的组队比赛就只有下个月中旬的省赛了

但6.1和6.2还有沟槽的蓝桥杯和百度之星,经典裸泳时间希望别被吊打的说

标签:Province,std,CI,Contest,int,auto,Programming,include,define
From: https://www.cnblogs.com/cjjsb/p/18196299

相关文章

  • AtCoder Regular Contest 177
    AtCoderRegularContest177A-Exchange问题陈述判断\(n\)个价格分别为\(x_i\)的商品,问能否通过有限数量的\(1\)元,\(5\)元,\(10\)元,\(50\)元,\(100\)元,\(500\)元,购买。思路贪心。每个商品从\(500\)元开始,能用就尽量用。如果中间某个商品无法被满足,则无解,反......
  • AtCoder Beginner Contest 351 E - Jump Distance Sum
    题目链接Hint1:只能斜着走,容易想到黑白棋盘,\((x+y)\%2==0\)位于一个团,\((x+y)\%2==1\)位于另一个团,分别求和。Hint2:\(dist=max(|x1-x2|,|y1-y2|)\),这是切比雪夫距离,将坐标系倾斜\(45^{\circ}\),改为曼哈顿距离\(dist=|x1-x2|+|y1-y2|\),即\(X=x+y,Y=x-y\),这样就可以将横纵坐标......
  • 2024 ICPC National Invitational Collegiate Programming Contest, Wuhan Site
    2024ICPCNationalInvitationalCollegiateProgrammingContest,WuhanSiteI.CyclicAppleStrings题意:给定一个01字符串,每次操作可以将这个字符串向左循环移动任意次数,求让这个字符串变成有序的需要最少几次操作思路:每次只能减少最右边的不和有边界相邻的一个1的长块,每次......
  • 2024 Jiangsu Collegiate Programming Contest
    Preface这场由于是学长们出的题,在5.5就作为验题队伍VP了一遍本来验题场一般是三人三机火速开题的,但由于那天徐神没带电脑,索性就三人一机当作训练来打最后经典被队友带飞,4h8题后和NJU的WF银牌队只差一题,然后最后1h我冲刺H题失败,耻辱下机吃花雕A.Two'sCompanybutThree'sTr......
  • AtCoder Beginner Contest 352 E - Clique Connect
    题目链接不需要将所有边都建立出来,根据\(Kruskal\)最小生成树的贪心策略,相同权值的边不需要形成团,形成一个链就行,对结果没有影响。时间复杂度\(O(mlogm)[m=\sum_{i=1}^{n}k_{i}]\)。#pragmaGCCoptimize(2)#pragmaGCCoptimize(3)#include<bits/stdc++.h>//#defineint......
  • AtCoder Beginner Contest 353
    AtCoderBeginnerContest353abc353_c题意:定义\(F(x,y)\)为\((x+y)mod10^8\)的值,求\(\displaystyle\sum_{i=1}^{N-1}\sum_{j=i+1}^Nf(A_i,A_j).\)思路:对于\(\displaystyle\sum_{i=1}^{N-1}\sum_{j=i+1}^N\f(A_i,A_j).\)来说,每个\(A_i\)的次数都是\(n-1\)次,所以如果没有\(m......
  • Atcoder Beginner Contest 353
    AtcoderBeginnerContest353A问题陈述有\(N\)幢楼房排列成一排。左起的\(i\)th楼高\(H_i\)。请判断是否有比左起第一座高的建筑物。如果存在这样的建筑物,请找出从左边起最左边的建筑物的位置。思路签到题。代码#include<bits/stdc++.h>usingnamespacestd;int......
  • AtCoder Beginner Contest 353
    AtCoderBeginnerContest353A-Buildings求第一个\(h_i\)大于\(h_1\)的位置。模拟。点击查看代码#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;intn,h[103];signedmain(){ cin>>n;cin>>h[1]; for(inti=2;i<=n;i++){ cin&......
  • AtCoder Beginner Contest 353
    A-Buildings(abc353A)题目大意给定\(n\)个数字,输出第一个大于第一个数的下标。解题思路依次与第一个数比较,大于则输出。神奇的代码n=input()a=list(map(int,input().split()))b=[i>a[0]foriina]ifTruenotinb:print(-1)else:print(b.ind......
  • 探究:响应式编程(Reactive Programming)
    在当今软件开发领域,响应式编程(ReactiveProgramming)成为了一个备受关注的话题。它提供了一种新的编程范式,与传统的命令式编程有着显著的不同。本文将详细讲解什么是响应式编程,以及它与传统的命令式编程的不同之处。1.什么是响应式编程?响应式编程是一种编程范式,它基于数据流和变......