A、给你一堆圆,问你能否从左上角走到右下角不经过所有圆

一种经典套路题,考虑使用并查集判联通,如果两圆相交,就把他们合并,如果圆与边界相交则合并圆与边界

最后判断一下边界能否互相抵达即可

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=10005;
const double eps=1e-9;

int n,m,k;
struct node{
    double x,y,r;
}o[N];
int f[N];
int _find(int x){
    if(f[x]!=x) f[x]=_find(f[x]);
    return f[x];
}
void _merge(int x,int y){
    x=_find(x),y=_find(y);
    if(x!=y) f[x]=y;
}

double dis(node a,node b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

bool smlepl(double a,double b){
    if(a<b||fabs(a-b)<eps) return 1;
    return 0;
}

void gao(){
    for(int i=1;i<=k+4;++i)
        f[i]=i;
    int x0=k+1,y0=k+2,xm=k+3,yn=k+4;
    for(int i=1;i<=k;++i){
        for(int j=1;j<=k;++j){
            if(i==j) continue;
            if(smlepl(dis(o[i],o[j]),o[i].r+o[j].r))
                _merge(i,j);
        }
        if(o[i].y-o[i].r<=0) _merge(i,y0);
        if(o[i].y+o[i].r>=n) _merge(i,yn);
        if(o[i].x-o[i].r<=0) _merge(i,x0);
        if(o[i].x+o[i].r>=m) _merge(i,xm);
    }
    if(_find(y0)==_find(yn)||_find(x0)==_find(xm)||
    _find(x0)==_find(y0)||_find(xm)==_find(yn))
        puts("N");
    else puts("S");
}

int main(){
    scanf("%d%d%d",&m,&n,&k);
    for(int i=1;i<=k;++i)
        scanf("%lf%lf%lf",&o[i].x,&o[i].y,&o[i].r);
    gao();
    return 0;
}

B、签到,判断第一个数是不是最大的那一个

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1e4+5;

int n,a[N];

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
        scanf("%d",&a[i]);
    int mx=-0x3f3f3f3f;
    int pos=-1;
    for(int i=1;i<=n;++i){
        if(a[i]>mx){
            mx=a[i];
            pos=i;
        }
    }
    if(pos==1) puts("S");
    else puts("N");
    return 0;
}

D、给定一棵树,你需要选择k个叶子,标记从这些叶子到根节点路径上的所有节点
问最多有几个节点被标记

考虑长链剖分,用树链剖分的套路,详见:树链剖分

选出最长的k条链即可

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;

int n,k;
int f[N],dep[N],len[N],son[N],top[N];
vector<int> e[N];
vector<int> tmp;

void d1(int x){
    len[x]=1;
    for(auto y:e[x]){
        dep[y]=dep[x]+1;
        d1(y);
        len[x]=max(len[x],len[y]+1);
        if(len[y]>len[son[x]]) son[x]=y;
    }
}

void d2(int x,int t){
    top[x]=t;
    if(e[x].size()==0){
        tmp.push_back(dep[x]-dep[top[x]]+1);
        return;
    }
    if(son[x]) d2(son[x],t);
    for(auto y:e[x]){
        if(y!=son[x]) d2(y,y);
    }
}

void gao(){
    int leaf=0;
    for(int i=1;i<=n;++i)
        if(e[i].size()==0) leaf++;
    if(k>=leaf){
        printf("%d",n);
        return;
    }
    dep[1]=1;
    d1(1);
    d2(1,1);
    sort(tmp.begin(),tmp.end(),greater<int>());
    int ans=0;
    for(int i=0;i<k;++i) ans+=tmp[i];
    printf("%d",ans);
}

int main(){
    scanf("%d%d",&n,&k);
    f[1]=0;
    for(int i=2;i<=n;++i)
        scanf("%d",&f[i]),e[f[i]].push_back(i);
    gao();
    return 0;
}
/*
9 2
1 1 3 2 5 6 7 7
*/

H、有个人在跑步,给定每圈的标志个数和他总路程的圈数,问你他在完成10%、20%......90%路程之后经过了几个标志

直接算即可,记得向上取整

代码:

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

int v,n;

int main(){
    scanf("%d%d",&v,&n);
    for(int i=1;i<=9;i++){
        printf("%d ",((v*n*i)+9)/10);
    }
    return 0;
}

L、题意比较怪,说的是两个人玩硬币,这是一枚不均衡的硬币,为了保证游戏公平,把这个硬币投掷n次,不同的情况对应着不同的人的胜利
问你把所有的情况分配给两个人,在保证两人获胜概率均等的情况下,最多能分配多少种情况

考虑什么情况下是获胜概率相等的两种情况,显然是1和0的数量相等的两种情况出现概率相同

打表找规律,发现规律就是2的(n的二进制表示下1的个数)次方

**这里被__builtin_popcount()坑死了,因为它只能计算int中的1的个数**

代码:

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

ll n;

int gao(ll n){
    int ans=0;
    while(n){
        if(n&1) ans++;
        n/=2;
    }
    return ans;
}

int main(){
    cin>>n;
    cout<<(1ll<<gao(n));
    return 0;
}

M、c个人和n个任务,每个人会分到连续的一段任务,单位时间一个人可以完成t个任务,问完成任务的最短时间是多少

二分时间即可,贪心地分配任务,能完成就尽量完成,否则分配给下一个人,最后看需要的人数是否小于c

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
typedef long long ll;

int n,c,t;
int a[N];

bool chk(ll now){
    int cnt=0,sum=0;
    for(int i=1;i<=n;++i){
        if(a[i]>now*t) return 0;
        if(sum+a[i]<=now*t)
            sum+=a[i];
        else{
            cnt++;
            sum=a[i];
        }
    }
    if(sum!=0) cnt++;
    return cnt<=c;
}

ll half(ll l,ll r){
    while(l<=r){
        ll m=(l+r)/2;
        if(chk(m)) r=m-1;
        else l=m+1;
    }
    return l;
}

int main(){
    scanf("%d%d%d",&n,&c,&t);
    for(int i=1;i<=n;++i)
        scanf("%d",&a[i]);
    ll ans=half(1,1e10);
    printf("%lld",ans);
    return 0;
}
01-07 12:52