补题若干(二)

[https://www.luogu.com.cn/problem/AT_abc427_e](暴力+STL)

题意:

给出二维矩阵:T在的位置以及垃圾#在的位置,每次可以使所有#向上/下/左/右移动一次,求使得垃圾不到T而全部被移除的最小操作次数

思路:

用一个set存所有#现在的位置,BFS每次枚举4个方向,map去重状态

int n,m;
queue<pair<set<pii>,int>>q;
pii sx;
const int dx[]={1,-1,0,0};
const int dy[]={0,0,1,-1};
map<set<pii>,int>vis;
void solve(){
    cin>>n>>m;
    set<pii>st;
    rep(i,1,n){
        rep(j,1,m){
            char k;cin>>k;
            if(k=='#')st.insert({i,j});
            else if(k=='T')sx={i,j};
        }
    }

    q.push({st,0});
    while(q.size()){
        auto[Set,step]=q.front();q.pop();
        if(vis.count(Set))continue;
        vis[Set]=1;
        if(Set.size()==0){
            cout<<step<<endl;return;
        }
        for(int i=0;i<4;i++){
            set<pii>newset;
            int ok=1;
            for(auto[x,y]:Set){
                int nx=x+dx[i],ny=y+dy[i];
                if((pii){nx,ny}==sx){
                    ok=0;break;
                }
                if(nx<1||nx>n||ny<1||ny>m)continue;
                newset.insert({nx,ny});
            }
            if(ok)q.push({newset,step+1});
        }
    }
    cout<<-1<<endl;
}

(https://www.luogu.com.cn/problem/AT_abc424_e)[优先队列+暴力]

题意:

\(n\)个树枝,进行\(k\)次的将最长的树枝长度减半的操作,求操作后第\(x\)长的树枝长度

思路:

竟能优先队列模拟:存一个pair,分别表示这个数和这个数的出现次数,模拟即可
时间复杂度O(nlogklogn)

int n,k,x;
void solve(){
    cin>>n>>k>>x;
    priority_queue<pair<double,int>>pq;
    rep(i,1,n){
        int x;cin>>x;
        pq.push({x*1.0,1});
    }
    while(k>0){
        auto[u,cnt]=pq.top();pq.pop();
        if(k>=cnt){
            pq.push({u/2,cnt*2});
            k-=cnt;
        }else{
            pq.push({u/2,k*2});
            pq.push({u,cnt-k});
            k=0;
        }
    }
    while(pq.size()){
        auto[u,cnt]=pq.top();
        if(x>cnt){
            pq.pop();x-=cnt;
        }else{
            cout<<fixed<<setprecision(18)<<u<<endl;
            return;
        }
    }
}

(https://atcoder.jp/contests/abc422/tasks/abc422_e)[随机化]

题意:

给定\(n\)个点的坐标,求一条能通过\((n+1)/2\)个点的直线方程

思路:

随机取一个点,在这条直线上的概率为\(1/2\)
那么取两个点确定一条直线,check一下就可以了

#define int __int128
#define gc getchar()
#define cin(a) a=read()
int read(){
    int x=0;bool fl=0;char s=gc;
    while(!isdigit(s)){if(s=='-')fl=1;s=gc;}  // 处理符号位
    while(isdigit(s))x=(x<<1)+(x<<3)+s-'0',s=gc;  // 计算数值,相当于x = x*10 + (s-'0')
    return fl?-x:x;
}
void Print(int x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x/10) Print(x/10);  // 递归输出高位
    putchar(x%10+'0');     // 输出当前位
}
int n;

//ax1+by1+c=0
//ax2+by2+c=0
//a(x1-x2) = -b(y1-y2)
//b = (x1-x2)/(y2-y1)a
//ax1+(x1-x2)*y1/(y2-y1)*a+c=0

void solve(){
    cin(n);
    vector<pii>a(n+1);
    rep(i,1,n){
        cin(a[i].fi);
        cin(a[i].se);
    }

    for(int _=1;_<=1e2;_++){
        int i=rnd()%n+1;
        int j=rnd()%n+1;
        while(i==j)j=rnd()%n+1;
        int x=a[i].fi,y=a[i].se,xx=a[j].fi,yy=a[j].se;
        int A = (y-yy);
        int B = (xx-x);
        int C = (yy*x-xx*y);
        int g=__gcd(A,__gcd(B,C));
        A/=g;
        B/=g;
        C/=g;
        int cnt=0;
        for(int __=1;__<=n;__++){
            int X = a[__].fi,Y=a[__].se;
            if(A*X+B*Y+C==0)cnt++;
        }
        if(cnt>=(n+1)/2){
            cout<<"Yes"<<endl;
            Print(A);
            putchar(' ');
            Print(B);
            putchar(' ');
            Print(C);
            return;
        }
    }
    cout<<"No"<<endl;
}
posted @ 2025-11-08 10:45  Marinaco  阅读(2)  评论(0)    收藏  举报
//雪花飘落效果