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\n",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\n",_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\n",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\n");
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\n");
74         }
75         else{
76             printf("Yes\n");
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\n",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\n",cnt,sum-ans);
29 
30     return 0;
31 }
View Code

 

posted @ 2016-10-24 20:45  N维解析几何  阅读(217)  评论(0编辑  收藏  举报