码迷,mamicode.com
首页 > 其他好文 > 详细

2016.6.13 考试总结

时间:2016-06-14 23:50:24      阅读:312      评论:0      收藏:0      [点我收藏+]

标签:

一、哲哲回家

【题目描述】:

哲哲放学了,准备坐公交车回家。因为急着回家看MSN战士,所以他想用最短的时间回家,但是因为学校离家里比较远,有时候他需要转几趟车才可以回家。等车是需要一段时间的,而且每辆公交车的速度不一样,哲哲晕掉了,不知道怎样才可以在最短的时间里回家,作为一名cjoier,你应该帮帮他。

现在一直哲哲所在的城市有N个公交站点(学校在一号站点,哲哲家在N号站点)和M条公交线路,每条公交线路是一个有序集合,公交线路i包含Pi个站点a[i,1],a[i,2]…a[i,Pi],表示i号公交车从a[i,1]出发,经过a[i,2],a[i,3]…a[i,Pi]又重新回到a[i,1]。

Ti,Ri分别表示等第i号公交车的时间和第i号公交车经过一站的时间(如果你当前处在第i条公交线路上,你可以花Ti的时间等到这辆车,然后这辆车会花Ri的时间经过一站,下车时间忽略不计)。

【输入】:

第一行两个数N,M,表示公交站点数和公交线路数。

以下M行,第i+1行每行前三个数为Ti,Ri,Pi,然后接着有Pi个数,第j+3个数表示a[i,j]。

【输出】:

仅一行,表示所需的最少时间。

【样例输入】:

3 3

3 3 3 1 2 3

10 1 2 1 3

1 1 2 3 2

【样例输出】:

8

【说明】:

哲哲从学校(1)出发坐1号公交车在2号站下,再从2号站转3号车到家。

20%的数据N,M≤10;

60%的数据N,M≤100;

100%的数据N,M≤500;Pi≤30。

 

  这实在是一道大水题,连边后跑一边最短路即可。连边的方式有两种:把每一条公交线路上的点两两连边,或把每个点拆成m个点,表示做哪一条线路过来。我写的第二种。代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<queue>
 7 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
 8 #define maxn 100010
 9 #define INF (1LL<<50)
10 #ifdef WIN32
11 #define OT "%I64d"
12 #else
13 #define OT "%lld"
14 #endif
15 
16 using namespace std;
17 typedef long long llg;
18 
19 struct data{
20     int now,from;
21     llg dis;
22     data(int a=0,int b=0,llg c=0):now(a),from(b),dis(c){};
23     bool operator < (const data &h)const {return dis>h.dis;}
24 }k;
25 int n,m,ti[510],ri[510]; llg f[510][510],ans;
26 int head[maxn],next[maxn],to[maxn],c[maxn],tt;
27 priority_queue<data>q;
28 
29 int getint(){
30     int w=0,q=0;
31     char c=getchar();
32     while((c<0||c>9)&&c!=-) c=getchar();
33     if(c==-) q=1,c=getchar();
34     while(c>=0&&c<=9) w=w*10+c-0,c=getchar();
35     return q?-w:w;
36 }
37 
38 void link(int x,int y,int z){
39     to[++tt]=y;next[tt]=head[x];head[x]=tt;
40     //to[++tt]=x;next[tt]=head[y];head[y]=tt;
41     //c[tt]=c[tt-1]=z;
42     c[tt]=z;
43 }
44 
45 void Dijstra(){
46     for(int i=0;i<=n;i++)
47         for(int j=0;j<=m;j++) f[i][j]=INF;
48     f[1][0]=0;
49     q.push(data(1,0,0));
50     while(!q.empty()){
51         k=q.top();q.pop();
52         int u=k.now,xx=k.dis,ff=k.from;
53         if(xx==f[u][ff])
54             for(int i=head[u],v;v=to[i],i;i=next[i]){
55                 int jisuan=ti[c[i]]+ri[c[i]];
56                 if(c[i]==ff) jisuan-=ti[c[i]];
57                 if(f[v][c[i]]>xx+jisuan){
58                     f[v][c[i]]=xx+jisuan;
59                     q.push(data(v,c[i],f[v][c[i]]));
60                 }
61             }
62     }
63     for(int i=0;i<=m;i++) ans=min(ans,f[n][i]);
64 }
65 
66 int main(){
67     File("home");
68     n=getint();m=getint();
69     for(int i=1,x,la,now,ll;i<=m;i++){
70         ti[i]=getint();ri[i]=getint();
71         x=getint(); if(x) ll=la=getint();
72         for(int j=1;j<x;j++){
73             now=getint();
74             link(la,now,i);
75             la=now;
76         }
77         if(x) link(now,ll,i);
78     }
79     ans=INF;Dijstra();
80     printf(OT,ans);
81     fclose(stdin);fclose(stdout);
82     return 0;
83 }

二、旋转单词阵

【题目描述】:

背英语单词对于LD同学来说是一件巨大的工程,需要经过七七四十九遍背诵加九九八十一遍默写这单词才记得下来。LD想发明一种新的记忆方法使得他可以更加快速的记忆单词,他发现了一个有趣的事情,某一个长度为len单词旋转之后生成的新的len-1个单词,在把他们按字典序排序,形成的新矩阵会有很奇特的性质,比如code

code

odec

deco

ecod

再把他们按字典序排序:

code

deco

ecod

odec

可以发现最后一列的单词为eodc,LD在想,能不能只记下最后一列单词就可以还原出整个单词矩阵呢?当然,因为这个矩阵中的单词有很多是无用的,所以他只要你输出第一行就可以了(也就是字典序最小的单词)。

【输入】:

    仅一行,表示最后一列的单词(为小写字母构成)。

【输出】:

仅一行,表示第一行的单词。

【样例输入】:

    eodc

【样例输出】:

    code

【说明】:

样例说明见题目描述。

20%的数据保证单词长度≤10;

60%的数据保证单词长度≤500;

100%的数据保证单词长度≤300000;

 

  这道题真是太神辣!IOI2001的预备题啊!不过为什么标解这么简单啊!

  我们可以将得到的单词排个序,不难发现我们就得到了每一个字母之后对应着那个字母。但重复的字母怎么办呢?我们排序时可以考虑加入第二关键字,即这个字母是第几次出现。因为若单词首字母相同,那么我们就可以根据我们得到的字母的顺序来确定先选哪一个了。自己想一想就可以明白了。我考场上为什么没有想出来啊!代码:

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<cmath>
 7 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
 8 #define maxn 300010
 9 
10 using namespace std;
11 typedef long long llg;
12 
13 struct data{
14     int x,b,bb;
15     data(int a=0,int b=0):x(a),b(b){}
16     bool operator < (const data &h)const{
17         if(x==h.x) return b<h.b;
18         return x<h.x;
19     }
20 }a1[maxn],a2[maxn];
21 char s[maxn];
22 int n=1,a[31];
23 
24 int main(){
25     File("word");
26     while(scanf("%c",&s[n])!=EOF){
27         a1[n].x=s[n]-a; a1[n].bb=n;
28         a1[n].b=++a[a1[n].x];
29         a2[n]=a1[n]; n++;
30     }
31     n--; sort(a2+1,a2+n+1);
32     for(int i=1,nn=1;i<=n;i++,nn=a2[nn].bb)
33         printf("%c",a2[nn].x+a);
34     fclose(stdin);fclose(stdout);
35     return 0;
36 }

三、切蛋糕

【题目描述】:

小J因为考试full mark被奖励了一个N*M的蛋糕,现在他想和大家分享这一个蛋糕。

划分的方法如下:每次选出已经分出的某一个矩形蛋糕将其一刀划分成两个小矩形,当然,这一刀可以选择横切或者竖切,最后被分成N*M块1*1的小蛋糕。

他希望统计出一共有多少种不同的划分方案,两个划分方案不同被定义为:其中任意一个划分方案的某一条刀痕在另一个划分方案中不存在。

【输入】:

仅一行两个数N,M。

【输出】:

仅一个数为方案数 mod 1024。

【样例输入】:

3 2

【样例输出】:

4

【说明】:

40%的数据N,M≤15;

100%的数据N,M≤300;

 

  这道题我们考虑dp做。不难想到用f[i][j]表示i行j列的矩形切割方案数。但是这样直接转移的话会有重复。于是我们加一维状态[0,1,2],0表示这一刀横竖都可以,1表示竖切,2表示横切,于是就可以转移了。横切一刀后上面那一块下一刀不可以横切,竖切类似。代码如下:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<ctime>
 7 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
 8 #define mod 1024
 9 
10 using namespace std;
11 
12 int n,m,f[310][310][3];
13 
14 int main(){
15     File("cake");
16     scanf("%d %d",&n,&m);
17     f[1][1][0]=f[1][1][1]=f[1][1][2]=1;
18     for(int x=1,now;x<=n;x++)
19         for(int y=1;y<=m;y++){
20             for(int i=1;i<x;i++){
21                 now=f[i][y][2]*f[x-i][y][0];
22                 f[x][y][0]+=now; f[x][y][1]+=now;
23                 f[x][y][0]%=mod; f[x][y][1]%=mod;
24             }
25             for(int i=1;i<y;i++){
26                 now=f[x][i][1]*f[x][y-i][0];
27                 f[x][y][0]+=now; f[x][y][2]+=now;
28                 f[x][y][0]%=mod; f[x][y][2]%=mod;
29             }
30         }
31     printf("%d",f[n][m][0]);
32     fclose(stdin);fclose(stdout);
33     return 0;
34 }

四、套圈游戏

【题目描述】:

Ly来到了一个游乐园,他刚刚进入就发现了一个他最喜欢玩的游戏,套圈游戏!

和很多普通的套圈游戏一样,在一个平面上有很多价值不同的礼品,当然ly希望用一个圈套住价值总尽量大的礼品。不过这个“圈”很特殊,是一个直角三角形,而且直角必须落在某个礼品上,现在给出你这个直角三角形的形状和礼品的位置和价值,问你怎样才可以套住总价值最大的礼品。

【输入】:

第一行一个整数N,表示有N个礼品。

第二行两个整数A,B,表示这个直角三角形的两个直角边的长度(A为平行于X轴的直角边的长度,B为平行于Y轴的直角边的长度),这个直角三角形不允许旋转,也就是说直角在最左下角。

接下来N行,第i+2行有三个整数Xi,Yi,Wi,表示礼品i的坐标(Xi,Yi)和价值Wi

【输出】:

仅一个数,表示最大价值。

【样例输入】:

4

5 5

1 7 100

1 1 2

2 2 99

7 1 100

【样例输出】:

101

【说明】:

40%的数据保证N≤5000;

100%的数据保证N≤100000;

100%的数据保证0<Xi,Yi≤10000,-10000<Wi<10000。

 

  容许我先%%%XYK大爷(这道题唯一的AC者)

  这道题用的方法很巧妙。考虑一个点B在以一个点A为左下角的三角形中需要满足什么条件。我们可以设直线l为那个直角三角形斜边过原点时的直线。当B到l的距离减去A到l的距离小于这个直角三角形的斜边上的高时可以计算(当B的x坐标与y坐标均>=A时)。于是我们可以把点按到l的距离从远到近排一遍序,然后不断加点、删点,用树状数组维护一下x轴、y轴的前缀和即可。代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
 7 #define maxn 100010
 8 
 9 using namespace std;
10 typedef long long llg;
11 
12 int cx[maxn/10],cy[maxn/10];
13 int n,_x,_y,A,B,ans,ll;
14 struct data{
15     int x,y,z,d;
16     bool operator < (const data &h)const{
17         return d<h.d;
18     }
19 }a[maxn];
20 
21 int getint(){
22     int w=0;bool q=0;
23     char c=getchar();
24     while((c>9||c<0)&&c!=-) c=getchar();
25     if(c==-) q=1,c=getchar();
26     while(c>=0&&c<=9) w=w*10+c-0,c=getchar();
27     return q?-w:w;
28 }
29 
30 void add(int x,int y,int z){
31     while(x<=_x) cx[x]+=z,x+=x&(-x);
32     while(y<=_y) cy[y]+=z,y+=y&(-y);
33 }
34 
35 int sum(int x,int y){
36     int t=0;
37     while(x) t+=cx[x],x-=x&(-x);
38     while(y) t+=cy[y],y-=y&(-y);
39     return t;
40 }
41 
42 int main(){
43     File("circle");
44     n=getint();A=getint();B=getint();
45     for(int i=1;i<=n;i++){
46         _x=max(a[i].x=getint(),_x);
47         _y=max(a[i].y=getint(),_y);
48         a[i].z=getint();
49         a[i].d=B*a[i].x+A*a[i].y;
50     }
51     sort(a+1,a+n+1);
52     for(int i=n,la=n;i;i--){
53         int now=a[i].z;
54         while(a[la].d-a[i].d>A*B){
55             add(a[la].x,a[la].y,-a[la].z);
56             ll-=a[la].z; la--;
57         }
58         now+=ll-sum(a[i].x-1,a[i].y-1);
59         ans=max(ans,now); ll+=a[i].z;
60         add(a[i].x,a[i].y,a[i].z);
61     }
62     printf("%d",ans);
63     return 0;
64 }

2016.6.13 考试总结

标签:

原文地址:http://www.cnblogs.com/lcf-2000/p/5585655.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!