B Buffoon

判断最大值是不是第一个数,签到题。

H Hour for a Run

输出\(n*m\)\(10\%\)\(90\%\),签到题,注意别用浮点数和ceil,有精度问题。

M Maratona Brasileira de Popcorn

题有点难读,就是给n个数,m个人,每人分一个连续段,每个数只能分给一个人,每人每秒最多把数字减k,问最少时间。

二分每一段的上界,贪心判断即可。

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+50;
int n,m,k,a[N];
bool check(int x){
    int c=1;
    int tmp=0;
    for(int i=1;i<=n;i++){
        if(a[i]>x){
            return false;
        }
        if(tmp+a[i]<=x){
            tmp+=a[i];
        }else{
            c++;
            tmp=a[i];
        }
    }
    return c<=m;
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    int sum=0;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        sum+=a[i];
    }
    int l=1,r=sum;
    int ans=0;
    while(l<=r){
        int mid=(l+r)/2;
        if(check(mid)){
            r=mid-1;
            ans=mid;
        }else{
            l=mid+1;
        }
    }
    printf("%d\n",(ans-1)/k+1);
    return 0;
}

D Denouncing Mafia

题意相当于给定一棵树,找出k条链使得覆盖的点最多。

  • 考虑贪心,每次肯定拿最长的一条链,然后拿走这条链后,树会变成一个森林,下一次再从这些树中取出最长链,再加入一些树

  • dfs一遍预处理出每个节点对应子树的最长链和删去最长链后得到的森林根节点,用一个优先队列贪心取即可。

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+55;
vector<int> g[N];
int ld[N];
vector<int> ls[N];
int n,k,f;
struct node{
    int u,w;
    bool operator<(const node& rhs)const{
        return w<rhs.w;
    }
};
void dfs(int u){
    int siz=g[u].size();
    if(!siz){
        ld[u]=1;
        return;
    }
    int mx=0;
    int k=0;
    for(int i=0;i<siz;i++){
        int v=g[u][i];
        dfs(v);
        if(ld[v]>mx){
            mx=ld[v];
            k=v;
        }
    }
    ld[u]=mx+1;
    for(int i=0;i<siz;i++){
        int v=g[u][i];
        if(v!=k){
            ls[u].push_back(v);
        }
    }
    int vs=ls[k].size();
    for(int j=0;j<vs;j++){
        ls[u].push_back(ls[k][j]);
    }
}
int main(){
    //freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&k);
    for(int i=2;i<=n;i++){
        scanf("%d",&f);
        g[f].push_back(i);
    }
    dfs(1);
    priority_queue<node> pq;
    pq.push({1,ld[1]});
    int ans=0;
    while(!pq.empty()){
        auto t=pq.top();
        int u=t.u;
        int w=t.w;
        pq.pop();
        ans+=w;
        k--;
        if(!k){
            break;
        }
        int siz=ls[u].size();
        for(int i=0;i<siz;i++){
            pq.push({ls[u][i],ld[ls[u][i]]});
        }
    }
    printf("%d\n",ans);
    return 0;
}

L Less Coin Tosses

题意本质就是长度为n的所有01串,0和1个数相同的可以匹配,找出不能匹配的01串个数。

  • 先考虑枚举0(或者1)的个数,这样的串有\(C_n^i\)个,那么这些串的01个数显然相同,如果偶数,可以一一匹配,如果是奇数,答案加1。

  • 所以本质就是求\(\sum_{i=1}^n C_n^i\%2\),打表找规律,发现有一个递归翻倍的常见套路。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;
ll pw[115],f[115];
int cnt;
void init(){
    pw[0]=1;
    f[0]=pw[0]-1;
    for(int i=1;i<=105;i++){
        pw[i]=pw[i-1]*2;
        f[i]=pw[i]-1;
        if(pw[i]>(ll)1e18){
            cnt=i;
            break;
        }
    }
}
ll solve(int k,ll n){
    if(k==1){
        return 2ll;
    }
    ll mid=pw[k-1]/2;
    if(n<=mid){
        return solve(k-1,n);
    }else{
        return 2ll*solve(k-1,n-mid);
    }
}
int main(){
    init();
    scanf("%lld",&n);
    int k=lower_bound(f+1,f+1+cnt,n)-f;
    ll ans=solve(k,n-f[k-1]);
    printf("%lld\n",ans);
    return 0;
}

G Getting Confidence

给定\(n*n\)的矩阵,每列选一个数且不能同一行,使得乘积最大。

  • 做过类似套路的题目,将数求个对数,然后乘积最大就是和最大,然后网络流建图,限制每行每列,跑个最小费用最大流。
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+50;
const int INF=0x3f3f3f3f;
const double DINF=1.0*1e18;
const double eps=1e-8;
struct Edge{
    int u,v,w;
    double c;
    int next;
}e[N];
int ns,n,mt[105][105];
int cnt,head[N];
void init(){
    cnt=0;
    memset(head,-1,sizeof(head));
}
void add(int u,int v,int w,double c){
    e[cnt]=Edge{u,v,w,c,head[u]};
    head[u]=cnt++;
    e[cnt]=Edge{v,u,0,-c,head[v]};
    head[v]=cnt++;
}
double d[N];
int inq[N],s,t,p[N],a[N];
bool bf(int &flow,double &cost){
    for(int i=0;i<ns;i++){
        d[i]=DINF;
        inq[i]=0;
    }
    d[s]=0;
    p[s]=0;
    a[s]=INF;
    queue<int> q;
    q.push(s);
    inq[s]=1;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        inq[u]=false;
        for(int i=head[u];i!=-1;i=e[i].next){
            int v=e[i].v;
            int w=e[i].w;
            double c=e[i].c;
            if(w>0 && d[v]>d[u]+c){
                d[v]=d[u]+c;
                p[v]=i;
                a[v]=min(a[u],w);
                if(!inq[v]){
                    q.push(v);
                    inq[v]=1;
                }
            }
        }
    }
    if(fabs(d[t]-DINF)<eps){
        return 0;
    }
    flow+=a[t];
    cost+=d[t]*a[t];
    for(int u=t;u!=s;u=e[p[u]].u){
        e[p[u]].w-=a[t];
        e[p[u]^1].w+=a[t];
    }
    return 1;
}
void mcmf(int &flow,double &cost){
    flow=0;
    cost=0.0;
    while(bf(flow,cost));
}
int main(){
    //freopen("in.txt","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            scanf("%d",&mt[i][j]);
        }
    }
    ns=(n+2)*n+2;
    s=0,t=ns-1;
    init();
    for(int i=1;i<=n;i++){
        add(s,n*n+i,1,0.0);
    }
    for(int i=1;i<=n;i++){
        add(n*n+n+i,t,1,0.0);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            add(n*n+i,(j-1)*n+i,1,0.0);
            add((j-1)*n+i,n*n+n+j,1,-log10(mt[j][i]));
        }
    }
    int flow=0;
    double cost=0;
    mcmf(flow,cost);
    for(int i=n*n+1;i<=n*n+n;i++){
        for(int j=head[i];j!=-1;j=e[j].next){
            if(e[j].w==0){
                printf("%d",(e[j].v-1)/n+1);
                if(i==n*n+n){
                    printf("\n");
                }else{
                    printf(" ");
                }
                break;
            }
        }
    }
    return 0;
}

J Jar of Water Game

题意不清的模拟题...还好队友什么牌都玩过

n个人,每个人有4张牌,初始指定第k个人有一张万能牌且从他开始,每次选一张出现次数最少的牌给下一个人,如果有万能牌且不是刚拿到,必须把万能牌给下一个人,如果有多个牌出现次数一样小,给那个值小的。

胜利的状态定义为手上有4张相同的牌,不能有万能牌,如果有多少胜利状态的人,即相同牌值小的胜利。

#include <bits/stdc++.h>
using namespace std;
int idx(char c){
    if(c=='A'){
        return 1;
    }else if(c>='2' && c<='9'){
        return c-'0';
    }else if(c=='D'){
        return 10;
    }else if(c=='Q'){
        return 11;
    }else if(c=='J'){
        return 12;
    }else if(c=='K'){
        return 13;
    }else if(c=='X'){
        return 14;
    }
}
int n,k;
struct node{
    int cnt[15];
    int tm;
    bool has;
}a[1005];
char s[10];
int win(){
    int ans=0;
    int res=0x3f3f3f3f;
    for(int x=1;x<=n;x++){
        int mx=0;
        int mk=0;
        for(int i=1;i<=13;i++){
            mx=max(mx,a[x].cnt[i]);
            if(a[x].cnt[i]>mx){
                mx=a[x].cnt[i];
                mk=i;
            }
        }
        if(mx==4 && !a[x].has){
            if(mk<res){
                res=mk;
                ans=x;
            }
        }
    }
    return ans;
}
int get(int x){
    if(a[x].has && a[x].tm==1){
        return 14;
    }else{
        if(a[x].has){
            a[x].tm=1;
        }
        int mn=0x3f3f3f3f;
        for(int i=1;i<=13;i++){
            if(!a[x].cnt[i]){
      #include <bits/stdc++.h>
using namespace std;
int idx(char c){
    if(c=='A'){
        return 1;
    }else if(c>='2' && c<='9'){
        return c-'0';
    }else if(c=='D'){
        return 10;
    }else if(c=='Q'){
        return 11;
    }else if(c=='J'){
        return 12;
    }else if(c=='K'){
        return 13;
    }else if(c=='X'){
        return 14;
    }
}
int n,k;
struct node{
    int cnt[15];
    int tm;
    bool has;
}a[1005];
char s[10];
int win(){
    int ans=0;
    int res=0x3f3f3f3f;
    for(int x=1;x<=n;x++){
        int mx=0;
        int mk=0;
        for(int i=1;i<=13;i++){
            mx=max(mx,a[x].cnt[i]);
            if(a[x].cnt[i]>mx){
                mx=a[x].cnt[i];
                mk=i;
            }
        }
        if(mx==4 && !a[x].has){
            if(mk<res){
                res=mk;
                ans=x;
            }
        }
    }
    return ans;
}
int get(int x){
    if(a[x].has && a[x].tm==1){
        return 14;
    }else{
        if(a[x].has){
            a[x].tm=1;
        }
        int mn=0x3f3f3f3f;
        for(int i=1;i<=13;i++){
            if(!a[x].cnt[i]){
                continue;
            }
            mn=min(mn,a[x].cnt[i]);
        }
        for(int i=1;i<=13;i++){
            if(mn==a[x].cnt[i]){
                return i;
            }
        }
    }
}
int main(){
    //freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        for(int j=0;j<4;j++){
            int x=idx(s[j]);
            a[i].cnt[x]++;
        }
        a[i].has=false;
        a[i].tm=0;
    }
    a[k].has=true;
    int cur=k;
    while(true){
        if(int w=win()){
            printf("%d\n",w);
            return 0;
        }
        int nex=get(cur);
        int nt=cur%n+1;
        a[cur].cnt[nex]--;
        a[nt].cnt[nex]++;
        if(nex==14){
            a[cur].has=false;
            a[cur].tm=0;
            a[nt].has=true;
            a[nt].tm=0;
        }
        cur=nt;
    }
    return 0;
}
          continue;
            }
            mn=min(mn,a[x].cnt[i]);
        }
        for(int i=1;i<=13;i++){
            if(mn==a[x].cnt[i]){
                return i;
            }
        }
    }
}
int main(){
    //freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        for(int j=0;j<4;j++){
            int x=idx(s[j]);
            a[i].cnt[x]++;
        }
        a[i].has=false;
        a[i].tm=0;
    }
    a[k].has=true;
    int cur=k;
    while(true){
        if(int w=win()){
            printf("%d\n",w);
            return 0;
        }
        int nex=get(cur);
        int nt=cur%n+1;
        a[cur].cnt[nex]--;
        a[nt].cnt[nex]++;
        if(nex==14){
            a[cur].has=false;
            a[cur].tm=0;
            a[nt].has=true;
            a[nt].tm=0;
        }
        cur=nt;
    }
    return 0;
}