2020 年百度之星·程序设计大赛 - 初赛二部分题解

Problem A

模拟即可

Problem B

由题可知每一个点都在以一个点为圆心,固定距离为半径的圆周上运动,那么要距离最小,直觉告诉我们是在同一条直线上,且位于同侧,但是看数据量发现,直接计算会炸时间,那么我们可以看看,一个距离在总和中有多少贡献,然后公式计算一下,可以优化到常数的时间复杂度。

Problem C

模拟就可以了,我们遍历每一个时间点,然后看在这个时间点的时候和现在感染的人在同一个位置的人,标记它,并且把这个点给pop出当前的轨迹。

#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
#define rep(i,f_start,f_end) for (int i=f_start;i<=f_end;++i)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define MT(x,i) memset(x,i,sizeof(x) )
#define rev(i,start,end) for (int i=start;i<end;i++)
#define inf 0x3f3f3f3f
#define mp(x,y) make_pair(x,y)
#define lowbit(x) (x&-x)
#define MOD 1000000007
#define exp 1e-8
#define N 1000005 
#define fi first 
#define se second
#define pb push_back
typedef long long ll;
const ll INF=0x3f3f3f3f3f3f3f3f;
typedef vector <int> VI;
typedef pair<int ,int> PII;
typedef pair<int ,PII> PIII;
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
void check_max (int &a,int b) { a=max (a,b);}
void check_min (int &a,int b) { a=min (a,b);}
int tt;

int main () {
    scanf ("%d",&tt);
    while (tt--) {
        int n;
        scanf ("%d",&n);
        vector <queue <PII>> people (n);
        int time=0;
        for (int len,t,p,i=0;i<n;i++) {
            scanf ("%d",&len);
            rep (j,1,len) {
                scanf ("%d%d",&t,&p);
                people[i].push ({t,p});
                time=max (time,t);
            }           
        }
        vector <bool> sign (n,0);
        int pos[12]={0};
        sign[0]=true;
        rep (i,1,time) {
            rev (j,0,n) {
                if (sign[j]&&people[j].size ()&&people[j].front().first==i)
                   pos[people[j].front().second]=i;
            }
            rev (j,0,n) {
                if (people[j].size ()&&people[j].front().first==i) {
                    if (pos[people[j].front().second]==i) sign[j]=true;
                    people[j].pop ();
                }
               
            }
        }
        printf ("1");
        rep (i,2,n) if (sign[i-1]) printf (" %d",i);
        printf ("\n");
    }
    return 0;
}

Problem D

爆搜是赛后提交会超时,标程是二分?

#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
#define rep(i,f_start,f_end) for (int i=f_start;i<=f_end;++i)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define MT(x,i) memset(x,i,sizeof(x) )
#define rev(i,start,end) for (int i=start;i<end;i++)
#define inf 0x3f3f3f3f
#define mp(x,y) make_pair(x,y)
#define lowbit(x) (x&-x)
#define MOD 1000000007
#define exp 1e-8
#define N 1000005 
#define fi first 
#define se second
#define pb push_back
typedef long long ll;
const ll INF=0x3f3f3f3f3f3f3f3f;
typedef vector <int> VI;
typedef pair<int ,int> PII;
typedef pair<int ,PII> PIII;
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
void check_max (int &a,int b) { a=max (a,b);}
void check_min (int &a,int b) { a=min (a,b);}
string str;
int t,n;
map <int,int> mp;

void dfs (int cnt,int &ans,int sum[]) {
    if (cnt==10) {
        int k=inf;
        rev (i,0,5)  k=min (k,sum[i]);
        ans=min (ans,n-k);
        return ;
    }
    rev (i,0,5) {
        sum[i]+=mp[cnt];
        dfs (cnt+1,ans,sum);
        sum[i]-=mp[cnt];
    }
}

int main () {
    ios::sync_with_stdio (false);
    cin>>t;
    while (t--) {
      mp.clear ();
      cin>>n;
      rep (i,1,n) {
          cin>>str;
          mp[str.back ()-'0']++;
      }
      int ans=inf;
      int sum[5]={0};
      dfs (0,ans,sum);
      cout<<ans<<endl;
    }
    return 0;
}

Problem E

最小费用最大流,我们可以发现一共就只有六种情况,所以我们把这六种情况压成点,然后圆点出发连三种饮料,cap是数量,然后发别连向每种情况,并加上对于的费用,然后每种情况连接到汇点,cap是情况的个数

#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
#define rep(i,f_start,f_end) for (int i=f_start;i<=f_end;++i)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define MT(x,i) memset(x,i,sizeof(x) )
#define rev(i,start,end) for (int i=start;i<end;i++)
#define inf 0x3f3f3f3f
#define mp(x,y) make_pair(x,y)
#define lowbit(x) (x&-x)
#define MOD 1000000007
#define exp 1e-8
#define N 1000005 
#define fi first 
#define se second
#define pb push_back
typedef long long ll;
const int INF=0x3f3f3f3f;
typedef vector <int> VI;
typedef pair<int ,int> PII;
typedef pair<int ,PII> PIII;
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
void check_max (int &a,int b) { a=max (a,b);}
void check_min (int &a,int b) { a=min (a,b);}
const int maxn=5e4+10;
const int M=5e3+10;
int n,m,s,t,cnt=1,tt;
int head[maxn],dis[maxn],pre[maxn],incf[maxn];
int maxflow,mincost;
bool vis[maxn];
struct edge {
    int v,next,flow,cost;
}e[M<<1];

inline void add (int u,int v,int flow,int cost) {
    e[++cnt]= (edge) {v,head[u],flow,cost};
    head[u]=cnt;
}

inline void add_edge (int u,int v,int flow,int cost) {
   add (u,v,flow,cost);
   add (v,u,0,-cost);
}

inline bool spfa () {
    queue <int > q;
    MT (dis,0x3f);
    MT (vis,0);
    q.push (s);
    dis[s]=0;
    vis[s]=1;
    incf[s]=1<<30;
    while (q.size ()) {
        int x=q.front (); q.pop ();
        vis[x]=0;
        for (int i=head[x];i;i=e[i].next) {
           if (!e[i].flow) continue;
           int v=e[i].v;
           if (dis[v]>dis[x]+e[i].cost) {
               dis[v]=dis[x]+e[i].cost;
               incf[v]=min (incf[x],e[i].flow);
               pre[v]=i;
               if (!vis[v]) vis[v]=1,q.push (v);
           }
        }
    }
    if (dis[t]==inf) return 0;
    return dis[t];
}

inline void mcmf () {
    while (spfa ()) {
       int x=t;
       maxflow+=incf[t];
       mincost+=dis[t]*incf[t];
       int i;
       while (x!=s) {
           i=pre[x];
           e[i].flow-=incf[t];
           e[i^1].flow+=incf[t];
           x=e[i^1].v;
       }
    }
}
int main () {
    scanf ("%d",&tt);
    while (tt--) {
        MT (head,0);
        cnt=1; maxflow=0,mincost=0;
        int n,a,b,c;
        scanf ("%d%d%d%d",&n,&a,&b,&c);
        char str[4];
        vector <int> v(6);
        s=0,t=10;
        rep (i,1,n) {
            scanf ("%s",&str);
            if (strcmp (str,"012")==0) v[0]++;
            if (strcmp (str,"021")==0) v[1]++;
            if (strcmp (str,"102")==0) v[2]++;
            if (strcmp (str,"210")==0) v[3]++;
            if (strcmp (str,"201")==0) v[4]++;
            if (strcmp (str,"120")==0) v[5]++;
        }

            add_edge (s,1,a,0);
            add_edge (s,2,b,0);
            add_edge (s,3,c,0);

            add_edge (1,4,INF,-3);
            add_edge (1,5,INF,-3);
            add_edge (1,6,INF,-2);
            add_edge (1,7,INF,-1);
            add_edge (1,8,INF,-2);
            add_edge (1,9,INF,-1);

            add_edge (2,4,INF,-2);
            add_edge (2,5,INF,-1);
            add_edge (2,6,INF,-3);
            add_edge (2,7,INF,-2);
            add_edge (2,8,INF,-1);
            add_edge (2,9,INF,-3);

            add_edge (3,4,INF,-1);
            add_edge (3,5,INF,-2);
            add_edge (3,6,INF,-1);
            add_edge (3,7,INF,-3);
            add_edge (3,8,INF,-3);
            add_edge (3,9,INF,-2);

            add_edge (4,10,v[0],0);
            add_edge (5,10,v[1],0);
            add_edge (6,10,v[2],0);
            add_edge (7,10,v[3],0);
            add_edge (8,10,v[4],0);
            add_edge (9,10,v[5],0);
            mcmf ();
            printf ("%d\n",-mincost);
    }    
    return 0;
}

Problem G

我们可以发现,我们的最优策略就是在我可以先完成这个任务的时候,那么我们先完成这个任务但是不提交,我们可以在对方完成的前一秒提交好贱啊,这样就浪费了对面的最多时间,然后这个时候我们却在做其他题目,这是最贪心的做法了,然后写一个dp就可以了。

#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
#define rep(i,f_start,f_end) for (int i=f_start;i<=f_end;++i)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define MT(x,i) memset(x,i,sizeof(x) )
#define rev(i,start,end) for (int i=start;i<end;i++)
#define inf 0x3f3f3f3f
#define mp(x,y) make_pair(x,y)
#define lowbit(x) (x&-x)
#define MOD 1000000007
#define exp 1e-8
#define N 1000005 
#define fi first 
#define se second
#define pb push_back
typedef long long ll;
const ll INF=1e18+7;;
typedef vector <int> VI;
typedef pair<int ,int> PII;
typedef pair<int ,PII> PIII;
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;};
void check_max (int &a,int b) { a=max (a,b);}
void check_min (int &a,int b) { a=min (a,b);}
const int maxn=2e3+1;
int t;
vector <vector <ll>> dp (maxn,vector <ll> (maxn,0));
ll a[maxn],b[maxn];

int main () {
    scanf ("%d",&t);
    while (t--) {
        int n;
        scanf ("%d",&n);
        rep (i,1,n) scanf ("%lld",&a[i]);
        rep (i,1,n) {
            scanf ("%lld",&b[i]);
            b[i]+=b[i-1];
        }
        dp.assign (n+1,vector <ll> (n+1,INF));;
        dp[0][0]=0;
        rep (i,1,n) {
            rep (j,0,i) {
                if (dp[i-1][j-1]+a[i]>b[i]||j==0) dp[i][j]=dp[i-1][j];
                else dp[i][j]=min (dp[i-1][j],dp[i-1][j-1]+a[i]);
            }
        } 
        per (i,n,1) if (dp[n][i]!=INF) {
            printf ("%d\n",i);
            break;
        }
    }
    
    return 0;
}
posted @ 2020-09-30 21:24  Luglucky  阅读(240)  评论(0编辑  收藏  举报