[Offer收割]编程练习赛13 解题报告

http://hihocoder.com/contest/offers13/problems

题目1 : 风格不统一如何写程序

首先:输入保证组成变量名的单词只包含小写字母。

做法:只要对不同的部分进行修改即可

注意:只有一个单词,两个方法的单词都一样

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <stdbool.h>
 5 
 6 int main()
 7 {
 8     long n,i,k,len;
 9     char s[101];
10     bool vis;
11     scanf("%ld",&n);
12     for (k=1;k<=n;k++)
13     {
14         scanf("%s",s);
15         len=strlen(s);
16         vis=false;
17         for (i=0;i<len;i++)
18             if (s[i]=='_')
19             {
20                 vis=true;
21                 break;
22             }
23         if (vis)
24         {
25             for (i=0;i<len;i++)
26                 if (s[i]=='_')
27                 {
28                     printf("%c",s[i+1]-32);
29                     i++;
30                 }
31                 else
32                     printf("%c",s[i]);
33         }
34         else
35         {
36             for (i=0;i<len;i++)
37                 if (s[i]<97)
38                 {
39                     printf("_");
40                     printf("%c",s[i]+32);
41                 }
42                 else
43                     printf("%c",s[i]);
44         }
45         printf("\n");
46     }
47 
48     return 0;
49 }

最大子矩阵

注意:满足条件最大的子矩阵所包含的元素数目。如果没有子矩阵满足条件,输出-1。

与求最大子矩阵题目(hdu1559子矩阵的元素之和最大)方法类似。

设row[x][y]:第x行中前y个数的和

则row[x][q]-row[x][p]:第x行中第p+1~第q个数的和

行x~y列u~v的矩形的元素之和:row[x][v]-row[x][u-1]+row[x+1][v]-row[x+1][u-1]+…+row[y][v]-row[y][u-1]

按照列固定:u~v (第u个数到第v个数), 进行行的探索。

假设从行第p个数开始向下边2递增(每次p加1),假设到第q个数数值和第一次超过设定值,计算矩形面积(q-p)*(v-u+1),

然后从第p个数开始向下边1递增(每次p+1),直到数值和第一次小于设定值。

然后继续操作,直到v=n+1,结束。

而对于每个列固定:x~y,共m*m次。而对于每次行的探索,每个数最多加入一次,每个数最多减去一次,共2*n次。

时间复杂度O(m*m*n)。当然如果m>n,可以把行固定,进行列的探索,时间复杂度O(m*n*n)。

即时间复杂度O(m*n*min(m,n))。

参见程序,比较巧妙。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 long max(long a,long b)
 5 {
 6     if (a>b)
 7         return a;
 8     else
 9         return b;
10 }
11 
12 int main()
13 {
14     long n,m,f[260][260],row[260][260];
15     long i,j,s,t,maxg=0,maxvalue,ans=0,bian,x,y;
16     scanf("%ld%ld%ld",&n,&m,&maxvalue);
17     for (i=1;i<=n;i++)
18     {
19         //single row
20         row[i][0]=0;
21         for (j=1;j<=m;j++)
22         {
23             scanf("%ld",&f[i][j]);
24             row[i][j]=row[i][j-1]+f[i][j];
25         }
26     }
27     //s+1~t
28     for (s=0;s<m;s++)
29         for (t=s+1;t<=m;t++)
30         {
31             bian=t-s;
32             ans=0;
33             x=1;
34             y=1;
35             i=1;
36             while (i!=n+1)
37             {
38                 for (i=y;i<=n;i++)
39                 {
40                     ans=ans+row[i][t]-row[i][s];
41                     if (ans>maxvalue)
42                         break;
43                 }
44                 //x~i-1
45                 maxg=max(maxg,(i-x)*bian);
46                 //使x~i <=maxvalue
47                 //最终的可能性是减为0
48                 while (ans>=maxvalue)
49                 {
50                     ans=ans-row[x][t]+row[x][s];
51                     x++;
52                 }
53                 //使下一次从i+1的位置开始加
54                 y=i+1;
55 
56             }
57         }
58     if (maxg==0)
59         printf("-1\n");
60     else
61         printf("%ld\n",maxg);
62     return 0;
63 }
64 /*
65 5 5 3
66 1 2 3 2 1
67 2 3 1 2 3
68 1 2 1 3 1
69 1 2 1 3 1
70 1 2 3 3 3
71 */
72 /*
73 20 20 31
74 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
75 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
76 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
77 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
78 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
79 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
80 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
81 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
82 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
83 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
84 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
85 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
86 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
87 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
88 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
89 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
90 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
91 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
92 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
93 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
94 */

题目3 : 一人麻将

注意:无法胡牌输出-1。

方法:可以cheat!!!经测试,输出-1,可得10分。那时我去参加zoj的网赛,没有时间了,就果断cheat!(noip及其有效,对一些特殊且容易写的部分)

参见程序,程序长,但时间消耗比较短

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <stdbool.h>
  4 
  5 struct rec
  6 {
  7     long posu,posv;
  8 };
  9 
 10 struct node
 11 {
 12     long posu,posv,posw;
 13 };
 14 
 15 bool vis[108];
 16 struct node s[1800];
 17 long ts,ee,minpos=200;
 18 
 19 int cmp(const void *a,const void *b)
 20 {
 21     //posu<posv。对a,b中最大的牌(posv)进行升序排序(先拿到,先胡牌)
 22     //a,b中最大的牌(posv)都不相同
 23     return (*(struct rec *)a).posv - (*(struct rec *)b).posv;
 24 }
 25 
 26 int cmp1(const void *a,const void *b)
 27 {
 28     return (*(struct node *)a).posw - (*(struct node *)b).posw;
 29 }
 30 
 31 long max(long a,long b)
 32 {
 33     if (a>b)
 34         return a;
 35     else
 36         return b;
 37 }
 38 
 39 long min(long a,long b)
 40 {
 41     if (a>b)
 42         return b;
 43     else
 44         return a;
 45 }
 46 
 47 void dfs(long b,long step)
 48 {
 49     long i;
 50     for (i=b;i<ts-step && s[i].posw<minpos;i++)
 51         if (vis[s[i].posu] && vis[s[i].posv] && vis[s[i].posw])
 52         {
 53             if (step==0)
 54             {
 55                 //minpos=min(minpos,s[i].posw);
 56                 minpos=max(ee,s[i].posw);
 57                 break;
 58             }
 59             //else if (s[i].posw<minpos)
 60             else
 61             {
 62                 vis[s[i].posu]=false;
 63                 vis[s[i].posv]=false;
 64                 vis[s[i].posw]=false;
 65                 dfs(i+1,step-1);
 66                 vis[s[i].posu]=true;
 67                 vis[s[i].posv]=true;
 68                 vis[s[i].posw]=true;
 69             }
 70         }
 71 }
 72 
 73 int main()
 74 {
 75     char str[3];
 76     //一张牌最多4个:2对,9*2=18种牌
 77     //3:
 78     //数字相连:(1,2,3)~(7,8,9) 每张牌有4种选择 4*4*4*8=502
 79     //同数字:若有四张牌 1,2,3;2,3,4(若1,2,3与其它冲突,用2,3,4) 2*9=18
 80     struct rec er[3][30],e[90];
 81     struct node san[3][600];
 82     long ge[3],gs[3],te;
 83     //pai[i][j]:i:对应a,b,c j:对应1~9,最多有4张牌
 84     long n,x,y,t,pai[3][9][4],ans[3][9];
 85     long i,j,k,l,m;
 86     for (i=0;i<3;i++)
 87         for (j=0;j<9;j++)
 88             ans[i][j]=0;
 89     scanf("%ld",&n);
 90 
 91     for (i=0;i<14;i++)
 92     {
 93         scanf("%s",str);
 94         x=str[0]-97;
 95         //-'1'
 96         y=str[1]-49;
 97         pai[x][y][ans[x][y]]=i;
 98         ans[x][y]++;
 99     }
100     for (i=14;i<14+n;i++)
101     {
102         scanf("%s",str);
103         x=str[0]-97;
104         y=str[1]-49;
105         pai[x][y][ans[x][y]]=i;
106         ans[x][y]++;
107     }
108 
109     //对子
110     for (i=0;i<3;i++)
111     {
112         ge[i]=0;
113         for (j=0;j<9;j++)
114         {
115             //找最前面的配对
116             if (ans[i][j]>=2)
117             {
118                 er[i][ge[i]].posu=pai[i][j][0];
119                 er[i][ge[i]].posv=pai[i][j][1];
120                 ge[i]++;
121             }
122             //两个对子
123             if (ans[i][j]==4)
124             {
125                 er[i][ge[i]].posu=pai[i][j][2];
126                 er[i][ge[i]].posv=pai[i][j][3];
127                 ge[i]++;
128             }
129         }
130         qsort(er[i],ge[i],sizeof(struct rec),cmp);
131     }
132 
133     //至少拥有7个对子胡牌
134     //手中14张牌最多只能属于两个花色
135     //each 对子 没有相互影响
136     for (i=0;i<2;i++)
137         for (j=i+1;j<3;j++)
138             if (ge[i]+ge[j]>=7)
139             {
140                 x=0;
141                 y=0;
142                 t=0;
143                 while (x<ge[i] && y<ge[j] && t<6)
144                 {
145                     t++;
146                     if (er[i][x].posv<er[j][y].posv)
147                         x++;
148                     else
149                         y++;
150                 }
151                 if (t==6)
152                 {
153                     //use j
154                     if (x==ge[i])
155                         minpos=min(minpos,er[j][y].posv);
156                     //use i
157                     else if (y==ge[j])
158                         minpos=min(minpos,er[i][x].posv);
159                     else
160                         minpos=min(minpos,min(er[i][x].posv,er[j][y].posv));
161                 }
162                 //use j
163                 else if (x==ge[i])
164                     minpos=min(minpos,er[j][y+6-t].posv);
165                 //use i
166                 else
167                     minpos=min(minpos,er[i][x+6-t].posv);
168             }
169 
170     //三张牌
171     for (i=0;i<3;i++)
172     {
173         gs[i]=0;
174         //同数字
175         for (j=0;j<9;j++)
176         {
177             if (ans[i][j]>=3)
178             {
179                 san[i][gs[i]].posu=pai[i][j][0];
180                 san[i][gs[i]].posv=pai[i][j][1];
181                 san[i][gs[i]].posw=pai[i][j][2];
182                 gs[i]++;
183             }
184             if (ans[i][j]==4)
185             {
186                 //相同的牌先给别人用了
187                 san[i][gs[i]].posu=pai[i][j][1];
188                 san[i][gs[i]].posv=pai[i][j][2];
189                 san[i][gs[i]].posw=pai[i][j][3];
190                 gs[i]++;
191             }
192         }
193         //数字相连
194         for (j=0;j<7;j++)
195             for (k=0;k<ans[i][j];k++)
196                 for (l=0;l<ans[i][j+1];l++)
197                     for (m=0;m<ans[i][j+2];m++)
198                     {
199                         san[i][gs[i]].posu=pai[i][j][k];
200                         san[i][gs[i]].posv=pai[i][j+1][l];
201                         san[i][gs[i]].posw=pai[i][j+2][m];
202                         //posw存放最大值
203                         if (san[i][gs[i]].posu>san[i][gs[i]].posw)
204                         {
205                             if (san[i][gs[i]].posu>san[i][gs[i]].posv)
206                             {
207                                 t=san[i][gs[i]].posu;
208                                 san[i][gs[i]].posu=san[i][gs[i]].posw;
209                                 san[i][gs[i]].posw=t;
210                             }
211                             else
212                             {
213                                 t=san[i][gs[i]].posv;
214                                 san[i][gs[i]].posv=san[i][gs[i]].posw;
215                                 san[i][gs[i]].posw=t;
216                             }
217                         }
218                         else if (san[i][gs[i]].posv>san[i][gs[i]].posw)
219                         {
220                             t=san[i][gs[i]].posv;
221                             san[i][gs[i]].posv=san[i][gs[i]].posw;
222                             san[i][gs[i]].posw=t;
223                         }
224                         gs[i]++;
225                     }
226         qsort(san[i],gs[i],sizeof(struct node),cmp1);
227     }
228 
229     //4*3+2
230     for (i=0;i<2;i++)
231         for (j=i+1;j<3;j++)
232         {
233             for (k=0;k<108;k++)
234                 vis[k]=true;
235 
236             te=0;
237             for (k=0;k<ge[i];k++)
238                 if (er[i][k].posv<minpos)
239                 {
240                     e[te]=er[i][k];
241                     te++;
242                 }
243                 else
244                     break;
245             for (k=0;k<ge[j];k++)
246                 if (er[j][k].posv<minpos)
247                 {
248                     e[te]=er[j][k];
249                     te++;
250                 }
251                 else
252                     break;
253 
254             ts=0;
255             for (k=0;k<gs[i];k++)
256                 if (san[i][k].posw<minpos)
257                 {
258                     s[ts]=san[i][k];
259                     ts++;
260                 }
261                 else
262                     break;
263             for (k=0;k<gs[j];k++)
264                 if (san[j][k].posw<minpos)
265                 {
266                     s[ts]=san[j][k];
267                     ts++;
268                 }
269 
270             qsort(e,te,sizeof(struct rec),cmp);
271             qsort(s,ts,sizeof(struct node),cmp1);
272 
273             for (k=0;k<te;k++)
274             {
275                 if (e[k].posv<minpos)
276                 {
277                     ee=e[k].posv;
278                     vis[e[k].posu]=false;
279                     vis[e[k].posv]=false;
280                     dfs(0,3);
281                     vis[e[k].posu]=true;
282                     vis[e[k].posv]=true;
283                 }
284                 else
285                     break;
286             }
287         }
288     //No Solution: output -1
289     if (minpos==200)
290         printf("-1\n");
291     else
292         printf("%ld\n",minpos-13);
293     return 0;
294 }

题目拓展:

有n个人,参加一个活动

每一个人有一个不和谐值

每三个人一个队伍

有若干组队伍

每一个队伍的不和谐值为三人的不和谐值的最大值
而不和谐值越小,完成一个活动越快

要求从n个人从选出m个队伍,
其中不同队伍里不能有相同的人

使不和谐值最大的队伍的不和谐值最小,
从而使得所有队伍完成时间最短


当三个人
变为两个人
变为k个人

结果如何???

 

题目4 : 骑士游历

一个通俗的想法:f[k][i][j],第k步可以到达(i,j)的步法总数。
f[k+1][i][j]是在第k步的基础上走1步到达(i,j)的步法总数。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #define yu 1000000007
 4 
 5 int main()
 6 {
 7     long dx[8]={-2,-2,-1,-1,1,1,2,2};
 8     long dy[8]={-1,1,-2,2,-2,2,-1,1};
 9     long long f[2][12][12];
10     long n,r,c,i,j,k,step,pre,cur,x,y;
11     long long ans;
12     scanf("%ld%ld%ld",&n,&r,&c);
13     for (i=1;i<=8;i++)
14         for (j=1;j<=8;j++)
15             f[0][i][j]=0;
16     f[0][r][c]=1;
17     pre=0;
18     cur=1;
19     for (step=1;step<=n;step++)
20     {
21         for (i=1;i<=8;i++)
22             for (j=1;j<=8;j++)
23                 f[cur][i][j]=0;
24         for (i=1;i<=8;i++)
25             for (j=1;j<=8;j++)
26                 for (k=0;k<8;k++)
27                 {
28                     x=i+dx[k];
29                     y=j+dy[k];
30                     if (x>=1 && x<=8 && y>=1 && y<=8)
31                         f[cur][x][y]=(f[cur][x][y]+f[pre][i][j])%yu;
32                 }
33 
34         pre=pre ^ 1;
35         cur=cur ^ 1;
36     }
37     ans=0;
38     for (i=1;i<=8;i++)
39         for (j=1;j<=8;j++)
40             ans=(ans+f[pre][i][j])%yu;
41     printf("%lld\n",ans);
42     return 0;
43 }

满分做法:

二分思想,类似快速幂思想

f[k][x][y][u][v]:从(x,y)开始走k步到(u,v)总的走法

1.第k步到达第k+1步

f[k+1][x][y][u][v]=sum(f[k][x][y][p][q]+f[1][p][q][u][v])

2.第k步到达第2*k步

f[2*k][x][y][u][v]=sum(f[k][x][y][p][q],f[k][p][q][u][v])

快速幂:1->k,如10101=(((1*2+0)*2+1)*2+0)*2+1。(乘4次,加5次)

初始化f[1],只要创建四维数组即可。

 

时间复杂度:

1.第k步到达第2*k步:x,y,p,q,u,v可以取1~8:8*8*8*8*8*8=262144

最多执行log2(1000000000)<=30(向下取整)

262144*30=7864320

2.第k步到达第k+1步:f[k+1][x][y][u][v]=sum(f[k][x][y][p][q]+f[1][p][q][u][v]):计算每个x,y:8*8*8(走马,8种操作)=512

最多执行log2(1000000000)<=30(向下取整)

时间复杂度可以忽略不计

总的时间复杂度小于1000万,不会超时。

参见程序

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <math.h>
 4 #define yu 1000000007
 5 
 6 int main()
 7 {
 8     long dx[8]={-2,-2,-1,-1,1,1,2,2};
 9     long dy[8]={-1,1,-2,2,-2,2,-1,1};
10     long long f[9][9][9][9],t[9][9][9][9],ans;
11     long n,r,c,m,ch[32];
12     long x,y,p,q,u,v,k,i;
13 
14     scanf("%ld%ld%ld",&n,&r,&c);
15     for (x=1;x<=8;x++)
16         for (y=1;y<=8;y++)
17             for (u=1;u<=8;u++)
18                 for (v=1;v<=8;v++)
19                     f[x][y][u][v]=0;
20     for (u=1;u<=8;u++)
21         for (v=1;v<=8;v++)
22             for (k=0;k<8;k++)
23             {
24                 p=u-dx[k];
25                 q=v-dy[k];
26                 if (p>=1 && p<=8 && q>=1 && q<=8)
27                     f[p][q][u][v]=1;
28             }
29 
30     m=(long)(log(n)/log(2.0));
31     ch[0]=1;
32     for (i=1;i<=m;i++)
33         ch[i]=ch[i-1]<<1;
34     n-=ch[m];
35     for (i=m-1;i>=0;i--)
36     {
37         //*2
38         for (x=1;x<=8;x++)
39             for (y=1;y<=8;y++)
40                 for (u=1;u<=8;u++)
41                     for (v=1;v<=8;v++)
42                     {
43                         t[x][y][u][v]=f[x][y][u][v];
44                         f[x][y][u][v]=0;
45                     }
46 
47         for (x=1;x<=8;x++)
48             for (y=1;y<=8;y++)
49                 for (u=1;u<=8;u++)
50                     for (v=1;v<=8;v++)
51                     {
52                         f[x][y][u][v]=0;
53                         for (p=1;p<=8;p++)
54                             for (q=1;q<=8;q++)
55                 f[x][y][u][v]=(f[x][y][u][v]+t[x][y][p][q]*t[p][q][u][v])%yu;
56                     }
57         //+1
58         if (n>=ch[i])
59         {
60             for (x=1;x<=8;x++)
61                 for (y=1;y<=8;y++)
62                     for (u=1;u<=8;u++)
63                         for (v=1;v<=8;v++)
64                         {
65                             t[x][y][u][v]=f[x][y][u][v];
66                             f[x][y][u][v]=0;
67                         }
68 
69             for (u=1;u<=8;u++)
70                 for (v=1;v<=8;v++)
71                     for (k=0;k<8;k++)
72                     {
73                         p=u-dx[k];
74                         q=v-dy[k];
75                         if (p>=1 && p<=8 && q>=1 && q<=8)
76                         {
77                             for (x=1;x<=8;x++)
78                                 for (y=1;y<=8;y++)
79                             f[x][y][u][v]=(f[x][y][u][v]+t[x][y][p][q])%yu;
80                         }
81                     }
82             n-=ch[i];
83         }
84     }
85     ans=0;
86     for (u=1;u<=8;u++)
87         for (v=1;v<=8;v++)
88             ans=(ans+f[r][c][u][v])%yu;
89     printf("%lld",ans);
90     return 0;
91 }

 

posted @ 2017-04-11 23:02  congmingyige  阅读(330)  评论(0编辑  收藏  举报