• 2016-2017 ACM-ICPC, NEERC, Southern Subregional Contest解题报告


    a 题意:给n个数,每次可以选择2-5个数进行-1操作,当所有数都相等的时候停止,输出可能的最大值,并且输出任意一种方案,当x=0时进行操作,数不会再变小,并且操作次数不能超过10000

     分析:最大为最小数,最小为0,n最大100,数最大100,和为1000,每次选择两个数进行操作,也最多5000次,所以只要贪心取最大值,然后再考虑方案

     统计所有数的和假设答案的差,如果max*2<sum,那么必然可以找到一种操作方案,如果sum为奇数,就进行一次取三个最大的差,其余的取两个操作就行

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 const int maxn=1e2+5;
      4 struct node{
      5     int id,v;
      6     node(){}
      7     node(int _id,int _v):id(_id),v(_v){}
      8     bool operator < (const node& str)const {
      9         return v<str.v;
     10     }
     11 };
     12 int a[maxn],b[maxn],A[10005][maxn];
     13 int n,_min,cnt;
     14 priority_queue<node> q;
     15 
     16 bool test(int t){
     17     int sum=0,_max=-1;
     18     for(int i=1;i<=n;i++){
     19         int w=a[i]-t;
     20         _max=max(_max,w);
     21         sum+=w;
     22     }
     23     sum-=_max;
     24     //cout<<sum<<" "<<_max<<endl;
     25     return sum>=_max;
     26 }
     27 
     28 bool test1(){
     29     queue<node> qq;
     30     int num=q.top().v;
     31     bool ok=1;
     32     while(!q.empty()){
     33             node tmp=q.top();q.pop();
     34             qq.push(tmp);
     35             if(tmp.v!=num){ok=0;break;}
     36     }
     37     while(!qq.empty()){
     38         q.push(qq.front());
     39         qq.pop();
     40     }
     41     return ok;
     42 }
     43 void adde(node e){
     44     if(e.v==0)q.push(e);
     45     else q.push(node(e.id,e.v-1));
     46 }
     47 void add1(node e){
     48     if(e.v>0)q.push(node(e.id,e.v-1));
     49 }
     50 int main(){
     51     cin>>n;cnt=0;_min=105;
     52     for(int i=1;i<=n;i++){
     53         cin>>a[i];
     54         _min=min(_min,a[i]);
     55     }
     56     int ans=_min;
     57     for(;ans>0;ans--)if(test(ans))break;
     58     cout<<ans<<endl;
     59     if(ans==0){
     60         for(int i=1;i<=n;i++)q.push(node(i,a[i]));
     61          while(!test1()){
     62             node q1=q.top();q.pop();
     63             node q2=q.top();q.pop();
     64             adde(q1);
     65             adde(q2);
     66             A[cnt][q1.id]=A[cnt][q2.id]=1;
     67             cnt++;
     68         }
     69     }
     70     else{
     71         int ssum=0;
     72         for(int i=1;i<=n;i++){
     73             int w=a[i]-ans;ssum+=w;
     74             q.push(node(i,w));
     75         }
     76         while(!test1()){
     77             if(ssum&1){
     78                 node q1=q.top();q.pop();
     79                 node q2=q.top();q.pop();
     80                 node q3=q.top();q.pop();
     81                 ssum-=3;
     82                 add1(q1);add1(q2);add1(q3);
     83                 A[cnt][q1.id]=A[cnt][q2.id]=A[cnt][q3.id]=1;
     84                 cnt++;
     85             }
     86             else{
     87                 node q1=q.top();q.pop();
     88                 node q2=q.top();q.pop();
     89                 adde(q1);
     90                 adde(q2);
     91                 ssum-=2;
     92                 A[cnt][q1.id]=A[cnt][q2.id]=1;
     93                 cnt++;
     94             }
     95         }
     96     }
     97     //输出答案
     98     cout<<cnt<<endl;
     99     for(int i=0;i<cnt;i++){
    100         for(int j=1;j<=n;j++)
    101             printf("%d",A[i][j]);
    102         puts("");
    103     }
    104     return 0;
    105 }
    View Code

    b题意:人机问答,给出长度为n的数组,下标从1开始,每次你可以问? a b 表示询问评测机a b下标表示的数,哪个大,回答有= + -三种,要在[3*n/2]-2(表示向上取整)次操作内,询问出最大值和最小值的下标

    分析:没做这种人机问答的经验,fflush(stdout),挂了我全场,开始我认为是归并,貌似我归并写挂了,然后分析了下操作次数,开始将数i i+1两两比较,a数组存两个里面的较大值,b存较小值,次数是[n/2],然后一次循环询问最大值和最小值就行了,次数都是[n/2]-1,总次数不会超过要求

    #include<bits/stdc++.h>
    using namespace std;
    
    int a[100],b[100];
    char op;
    int test(int c,int d){
        printf("? %d %d
    ",c,d);
        cin>>op;
        if(op=='>')return 1;
        else if(op=='=')return 0;
        return -1;
    }
    
    int main(){
        int t,n;
        cin>>t;
        while(t--){
            cin>>n;
    
            fflush(stdout);
            int _max,_min,cnt=0;
            for(int i=1;i<=n;i+=2){
                if(i==n){
                    a[cnt]=b[cnt]=i;
                }
                else{
                    int w=test(i,i+1);
                    if(w==1)a[cnt]=i,b[cnt]=i+1;
                    else if(w==0)a[cnt]=b[cnt]=i;
                    else a[cnt]=i+1,b[cnt]=i;
                }
                cnt++;
            }
            _max=a[0];_min=b[0];
            for(int i=1;i<cnt;i++){
                int w=test(_max,a[i]);
                if(w==-1)_max=a[i];
            }
            for(int i=1;i<cnt;i++){
                int w=test(_min,a[i]);
                if(w==1)_min=a[i];
            }
            printf("! %d %d
    ",_min,_max);
        }
        return 0;
    }
    View Code

    c题意:n个城市,m条边,每条边长度都是1,然后有k个商店,gi ai,bi分别表示商店所在的城市,货物的数量,价格,然后有q次询问,ai,bi,ci表示ai城市需要bi个商品,总价格不能超过ci,输出所有向他运输产品的城市的最远距离,不存在答案输出-1

    分析:先计算所有城市之间的距离,bfs求最短里,时间复杂度O(n^2+n*m),边表示不超过n,对于cf飞快的评测机,5e7小意思,然后二分距离就行了,判断就先把所有商店按照价格排个序,然后判断就ok

    d:题意,给了n座桥,相邻的桥紧密连接,然后每座桥给出了长度和最长通过时间,你每分钟走0.5米,还有一种能量棒,每次使用持续r秒,r秒内每分钟走1米,求最少使用能量棒次数分析:能直接走过的桥肯定直接走过,l>t的桥,使用能量棒也无法通过,输出-1,不能直接走过去的桥,就要考虑使用能量棒,每次都是最后的那段时间一直持续在能量棒时间中,这样比在开头用有优势,那就是能量棒可能延伸到下一座或者下几座

    g题意:有n辆车,每个车都有一个开始修车的时间,和修车需要的时间,先安排先进入的车,该车的时间段内能修,则安排这个时间,否则找到一个最早的时间,最后输出所有车的修车开始 结束时间

    分析:模拟,开个结构体,里面两个元素,表示占用的时间的开始和结束,然后加入新安排的时候判断新加入是否已使用冲突,没冲突加入,冲突的话,开始时间肯定是某个结束时间+1,在占用时间里面价格(0,0),就可以解决1开始的问题

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=205;
     4 struct node{
     5     int s,e;
     6     node(int a=0,int b=0):s(a),e(b){}
     7     bool operator <(const node& str)const{return s<str.s;}
     8 }ans[maxn],p[maxn];
     9 int n,x1,x2;
    10 
    11 bool cmp(node a,node b){
    12     if(a.s>b.s)swap(a,b);
    13     if(a.e)return false;
    14     return true;
    15 }
    16 
    17 int main(){
    18     cin>>n;
    19     ans[0].s=ans[0].e=0;
    20     for(int i=1;i<=n;i++){
    21         scanf("%d%d",&x1,&x2);
    22         int a=x1,b=x1+x2-1;
    23         bool ok=1;
    24         for(int j=1;j<i;j++)if(!cmp(ans[j],node(a,b))){ok=0;break;}
    25         if(ok){
    26             p[i].s=ans[i].s=a;p[i].e=ans[i].e=b;
    27         }
    28         else{
    29             for(int j=0;j<i;j++){
    30                 a=ans[j].e+1;b=a+x2-1;
    31                 ok=1;
    32                 for(int k=1;k<i;k++)if(!cmp(ans[k],node(a,b))){ok=0;break;}
    33                 if(ok){
    34                     p[i].s=ans[i].s=a;p[i].e=ans[i].e=b;break;
    35                 }
    36             }
    37         }
    38         sort(ans+1,ans+i+1);
    39     }
    40     for(int i=1;i<=n;i++)
    41         printf("%d %d
    ",p[i].s,p[i].e);
    42     return 0;
    43 }
    View Code

    H题意:给n个字符串,然后给出m个选定的字符串,如果这m个字符串长度相同,则这m个字符串组成一个字符串,规则就是,某位置m个字符串都相等则是那个字符,否则就说?,然后?可以代表任意字符,询问是否存在字符串和组合的字符串匹配

    分析:模拟,注意都是?的字符串

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=1e5+5;
     4 typedef long long ll;
     5 typedef  unsigned long long ull;
     6 int n,m;
     7 string s[110];
     8 int de[110];
     9 int vis[110];
    10 int main(){
    11     //freopen("in.txt","r",stdin);
    12     //ios::sync_with_stdio(false);
    13     scanf("%d%d",&n,&m);
    14     memset(vis,0,sizeof(vis));
    15     for(int i=1;i<=n;i++){
    16         cin>>s[i];
    17         //cout<<s[i]<<endl;
    18     }
    19     int flag;
    20     for(int i=0;i<m;i++){
    21         scanf("%d",&de[i]);
    22         vis[de[i]]=1;
    23 
    24         if(i==0)
    25             flag=s[de[i]].size();
    26         else{
    27             if(flag!=s[de[i]].size()){
    28                 flag=0;
    29             }
    30         }
    31         //cout<<flag<<endl;
    32     }
    33     if(flag==0){
    34         printf("No
    ");
    35     }
    36     else{
    37         string out=s[de[0]];
    38         int y=out.size();
    39         for(int i=1;i<m;i++){
    40             for(int j=0;j<out.size();j++){
    41                     if(out[j]=='?')
    42                         continue;
    43                     if(s[de[i]][j]!=out[j])
    44                         out[j]='?',y--;
    45             }
    46         }
    47 
    48         int z1=0;
    49         for(int i=1;i<=n;i++){
    50             int z=0;
    51             if(vis[i]==1)
    52                 continue;
    53             if(s[i].size()!=out.size())
    54                 continue;
    55 
    56             for(int j=0;j<out.size();j++){
    57                 if(out[j]=='?')
    58                     continue;
    59                 if(s[i][j]==out[j])
    60                 {
    61                     z++;
    62                     //break;
    63                 }
    64                 else
    65                     break;
    66             }
    67             if(z==y){
    68                 z1=1;
    69                 break;
    70             }
    71         }
    72         if(z1==1){
    73             printf("No
    ");
    74         }
    75         else{
    76             printf("Yes
    ");
    77             cout<<out<<endl;
    78         }
    79     }
    80     return 0;
    81 }
    View Code

    I,某学校有n个人,每个人有两个技能值,编程技能和运动技能,现在要选出p个参加编程比赛,s个参加运动会,每个人只能参加一个比赛,使得参加对应比赛的sum(p)+sum(s)最大,并且输出一个组队方案分析:按照p排序,然后dp,dp[i][j],表示前i个选j个s的最大值,ans[i][j]表示选了s选了i,p肯定选钱p个s没选的人,这样就可以做了

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=3005;
     4 
     5 struct node{
     6     int id,p,s;
     7     bool operator < (const node& str)const{return p>str.p;}
     8 }q[maxn];
     9 
    10 int dp[maxn][maxn];
    11 bool ans[maxn][maxn];
    12 int n,p,s;
    13 
    14 void solve(int i,int j,int w,int ok){
    15     if(dp[i][j]<w){
    16         dp[i][j]=w;
    17         ans[i][j]=ok;
    18     }
    19 }
    20 
    21 int main(){
    22     scanf("%d%d%d",&n,&p,&s);
    23     for(int i=0;i<n;i++){
    24         scanf("%d",&q[i].p);q[i].id=i+1;
    25     }
    26     for(int i=0;i<n;i++)scanf("%d",&q[i].s);
    27     sort(q,q+n);
    28 
    29     for(int i=0;i<n;i++){
    30         for(int j=0;j<=min(i,s);j++){
    31             if(i-j<p)
    32                 solve(i+1,j,dp[i][j]+q[i].p,0);
    33             else
    34                 solve(i+1,j,dp[i][j],0);
    35             if(j<s)
    36                 solve(i+1,j+1,dp[i][j]+q[i].s,1);
    37         }
    38     }
    39 
    40     //输出答案
    41     printf("%d
    ",dp[n][s]);
    42     int i=n,j=s;
    43     vector<int> sa,sb;
    44     for(;i>0;i--){
    45         if(ans[i][j]){
    46             j--;
    47             sb.push_back(q[i-1].id);
    48         }
    49         else if(i-j<=p)
    50             sa.push_back(q[i-1].id);
    51     }
    52     for(auto& tt:sa)printf("%d ",tt);puts("");
    53     for(auto& tt:sb)printf("%d ",tt);puts("");
    54     return 0;
    55 }
    View Code

    J,有n个瓶子,每个瓶子有ai的水,瓶子大小为bi,要将所有的水倒到最少的瓶子里,输出最小的瓶子数和最少的到水量

    分析:按照瓶子大小排序,然后贪心选尽量大的瓶子,可以得到要选的瓶子数_min,接下来只要找到一个方案,选取_min个瓶子并且水量最大,答案就说sum-_max,dp就行了,费用就是瓶子大小,价值就是瓶子水量,只要找到费用大于等于sum的最大价值就行了,dp[i][j]表示选i个瓶子,花费j的最大价值,大量状态无法达到,为了节省时间和空间,采用map模拟

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=105;
     4 int a[maxn],b[maxn],c[maxn];
     5 int n,sum,_min,cnt,k;
     6 map<int,int> v[105];
     7 
     8 int main(){
     9     cin>>n;
    10     for(int i=1;i<=n;i++)cin>>a[i],sum+=a[i];
    11     for(int i=1;i<=n;i++)cin>>b[i],c[i]=b[i];
    12     sort(c+1,c+1+n);
    13     for(k=n;cnt<sum;k--)cnt+=c[k];
    14     cnt=n-k;
    15     v[0][0]=0;
    16     for(int i=1;i<=n;i++)
    17         for(int j=cnt-1;j>=0;j--){
    18             for(auto & ttt:v[j]){
    19                 int t1=ttt.first+b[i],t2=ttt.second+a[i];
    20                 v[j+1][t1]=max(v[j+1][t1],t2);
    21             }
    22         }
    23     int ans=0;
    24     for(auto& tt:v[cnt]){
    25         if(tt.first>=sum)
    26             ans=max(ans,tt.second);
    27     }
    28     printf("%d %d
    ",cnt,sum-ans);
    29 
    30     return 0;
    31 }
    View Code
  • 相关阅读:
    npm安装一直报错Error: Cannot find module 'lru-cache'
    vue使用ref获取元素
    WinForm 简易仿360界面控件
    【解决方案】macOS 打开微信视频电话其他应用音量变小问题
    ES服务的搭建(八)
    ES安装
    缓存一致性问题(七)
    多级缓存架构(六)
    掌握SKU和SPU关系及表设计(三)
    架构的搭建(一)
  • 原文地址:https://www.cnblogs.com/jihe/p/5994515.html
Copyright © 2020-2023  润新知