zoukankan      html  css  js  c++  java
  • 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 ("
    ");
        }
        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
    ",-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
    ",i);
                break;
            }
        }
        
        return 0;
    }
    
  • 相关阅读:
    浅析Java CompletionService
    经验总结13--EF配置
    消息摘要算法-HMAC算法
    03012_预处理对象executeQuery方法(实现数据库的查询)
    GO学习笔记:函数defer
    GO学习笔记:函数传值与传指针
    GO学习笔记:函数作为值、类型
    GO学习笔记:函数Panic和Recover
    GO学习笔记:import
    GO学习笔记:struct类型
  • 原文地址:https://www.cnblogs.com/hhlya/p/13756544.html
Copyright © 2011-2022 走看看