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

20170803

时间:2017-08-04 22:44:04      阅读:241      评论:0      收藏:0      [点我收藏+]

标签:pac   需要   pen   front   memset   nod   顺序   span   正整数   

今天早上依旧兴奋地考了一早上,一位AK了,但是分数出来让人失望,第三题着实打错了。

第一题是一道简单的题目,我用了,并查集和离散化。

盘子序列

(disk.cpp/c/pas)

【问题描述】

有n个盘子。盘子被生产出来后,被按照某种顺序摞在一起。初始盘堆中如果一个盘子比所有它上面的盘子都大,那么它是安全的,否则它是危险的。称初始盘堆为A,另外有一个开始为空的盘堆B。为了掩盖失误,生产商会对盘子序列做一些“处理”,每次进行以下操作中的一个:(1)将A最上面的盘子放到B最上面;(2)将B最上面的盘子给你。在得到所有n个盘子之后,你需要判断初始盘堆里是否有危险的盘子。

 

【输入格式】

输入到disk.in

输入文件包含多组数据(不超过10组)

每组数据的第一行为一个整数n

接下来n个整数,第i个整数表示你收到的第i个盘子的大小

【输出格式】

输出到disk.out

对于每组数据,如果存在危险的盘子,输出”J”,否则输出”Y”

【输入输出样例】

disk.in

disk.out

3

2 1 3

3

3 1 2

 

Y

J

【数据范围】

20%的数据保证n<=8

80%的数据保证n<=1,000

100%的数据保证1<=n<=100,000,0<盘子大小<1,000,000,000且互不相等

 但是,貌似其他人算法和我不一样,额,但是我这个很快的。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 
 8 const int NN=100007;
 9 
10 int n;
11 struct Node
12 {
13     int zhi,biao;
14 }a[NN];
15 int vis[NN],fa[NN];
16 
17 bool cmp(Node x,Node y){return x.zhi<y.zhi;}
18 void init()
19 {
20     for (int i=1;i<=n;i++)
21     {
22         scanf("%d",&a[i].zhi);
23         a[i].biao=i;
24     }
25     sort(a+1,a+n+1,cmp);
26     for (int i=1;i<=n;i++)
27         vis[a[i].biao]=i;
28     for (int i=0;i<=n;i++)
29         fa[i]=i;    
30 }
31 int find(int num)
32 {
33     if (fa[num]!=num) fa[num]=find(fa[num]);
34     return fa[num];
35 }
36 int main()
37 {
38     freopen("disk.in","r",stdin);
39     freopen("disk.out","w",stdout);
40     
41     while(~scanf("%d",&n))
42     {
43         init();
44         bool boo=0;
45         int outmax=-1;
46         for (int i=1;i<=n;i++)
47         {
48             if (boo) continue;
49             if (vis[i]>outmax) 
50             {
51                 outmax=vis[i];
52                 int x=find(fa[vis[i]-1]);
53                 fa[vis[i]]=x;
54             }
55             else
56             {
57                 int x=find(outmax);
58                 if (x!=vis[i]) boo=1;
59                 else fa[vis[i]]=find(vis[i]-1);
60             }
61         }
62         if (boo) printf("J\n");
63         else printf("Y\n");
64     }
65 }

桌子摆放

(table.cpp/c/pas)

【问题描述】

神犇kblack有很多小弟。

为了庆祝生日,kblack准备在家宴请小弟,他想要邀请尽可能多的小弟来参加他的聚会。他将会和小弟一起坐在一个巨大的长方形桌子上。这个桌子能坐下的人数等于它的周长。

kblack的家可以抽象成一个n*m的矩阵,其中每个位置可能是空地,也可能摆放有其他物品。kblack的桌子的边必须与家的边界平行,并且不能占用任何一个已经占用了的位置。

kblack的粉丝wangyurzee想搞个大新闻,所以他想知道,kblack最多能宴请多少个小弟。但他实在是太弱了,于是向你求助。

 

【输入格式】

输入文件为table.in

第一行2个正整数n、m,表示kblack家的长宽。

接下来n行,每行m个字符,描述kblack的家。其中”.”表示空地,”X”表示不是空地。

【输出格式】

输出文件为table.out

一行一个整数,表示kblack最多能宴请多少小弟。

【输入输出样例】

table1.in

table1.out

2 2

..

..

7

table2.in

table

                                                                                                                                               

9

【样例解释】

对于样例1,桌子可以占满整个家,所以其周长为8,减去kblack一人,所以他能宴请7个小弟。

【数据范围】

对于30%的数据,n,m<=1,00;

对于60%的数据,n,m<=4,00;

对于85%的数据,n,m<=1,000;

对于100%的数据,n,m<=1,500;

这道题,是txm讲过的,去年考了0分还是多少的,单调栈,但是貌似O(N^2M)也可以过,应该复杂度远远小于极限吧,额,怀疑数据随机出的。

第一次90分,不知道哪里错了,然后贴了一发xzp代码

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cmath>
 4 #include<iostream>
 5 #include<cstring>
 6 using namespace std;
 7 
 8 const int NN=1507,INF=1e9+7;
 9 
10 int n,m,ans;
11 int Right[NN][NN];
12 char s[1507];
13 bool boo[NN][NN];
14 
15 void init()
16 {
17     memset(boo,0,sizeof(boo));
18     memset(Right,0,sizeof(Right));
19     scanf("%d%d",&n,&m);
20     for (int i=1;i<=n;i++)
21     {
22         scanf("%s",s);
23         for (int j=0;j<m;j++)
24             if (s[j]==.) boo[i][j+1]=true;
25             else boo[i][j+1]=false;
26     }
27     for (int i=1;i<=n;i++)
28         for (int j=m;j>=1;j--)
29             if (boo[i][j]) Right[i][j]=Right[i][j+1]+1;
30             else Right[i][j]=0;
31 }
32 
33 int stack[NN],len[NN];
34 int mid_find(int num,int x)
35 {
36     int l=1,r=num,mid;
37     while (l<r)
38     {
39         mid=(l+r)>>1;
40         if (stack[mid]<x) l+=1;
41         else r=mid;
42     }
43     if (stack[l]<x) return num+1;
44     else return l;
45 }
46 void solve()
47 {
48     int top,maxbiao;
49     for (int j=1;j<=m;j++)
50     {
51         memset(len,0,sizeof(0));
52         top=0,maxbiao=INF;
53         for (int i=1;i<=n;i++)
54             if (boo[i][j]==false)
55             {
56                 top=0;
57                 len[0]=i;
58             }
59             else
60             {
61                 int x=mid_find(top,Right[i][j]);
62                 stack[x]=Right[i][j];
63                 len[x]=i,top=x;
64                 if (maxbiao>top) 
65                 {
66                     int MM=-1;
67                     for (int k=top;k>=1;k--)
68                         if (MM<stack[k]*2+(len[top]-len[k-1])*2)
69                         {
70                             MM=stack[k]*2+(len[top]-len[k-1])*2;
71                             maxbiao=k;
72                         }
73                 }
74                 else if (Right[i][j]*2>stack[maxbiao]*2+(i-len[maxbiao])*2) maxbiao=top;
75                 ans=max(ans,stack[maxbiao]*2+(len[top]-len[maxbiao-1])*2);
76             }
77     }
78     if (ans==0) printf("0\n");
79     else printf("%d\n",ans-1);
80 }
81 int main()
82 {
83     //freopen("table.in","r",stdin);
84     //freopen("table.out","w",stdout);
85     init();
86     solve();
87 }

这是自己的代码,维护,加了许多剪枝。

压轴题

(aknoip.pas/c/cpp)

【题目描述】

现在是NOIP2016 Day2的比赛现场,神犇subconscious0已经秒杀了前两题,再加上他Day1轻松AK,所以现在摆在他面前的就只有这一道压轴题了,只要AC此题,他就能AK NOIP。

根据题面,subconscious0飞快地在大脑中罗列了n个知识点,并且对其中m对知识点建立了联系。每一个联系(u,v,x,y)代表subconscious0从知识点u联想到知识点v需要花费x单位时间,而从知识点v联想到知识点u需要花费y单位时间。

subconscious0发现,他只要从知识点1,经过一系列的联想,再联想回知识点1,便可轻松AC此题。不过在联想中,除了知识点1,必须有其他至少2个知识点被联想到,并且除1外的其他知识点最多都只能被联想到一次。

一旦subconscious0发现不能通过联想法AC此题,那么他便会立即用YJQQQAQ的AC自动机来AC此题。

老年退役选手wangyurzee很想知道,subconscious0至少需要花多少单位时间才能AK NOIP,所以他找到了你,请你帮他计算。如果subconscious0会用AC自动机来AC此题,请输出-1。

 

【输入格式】

输入文件为aknoip.in

第一行2 个正整数n,m,意义如题。

接下来m 行每行4 个正整数u,v,x,y,描述了一个联系(u,v,x,y)。

数据保证每两个知识点之间最多有一个联系。

【输出格式】

输出文件为aknoip.out

一行一个整数表示答案。

【输入输出样例】

aknoip1.in

aknoip1.out

3 3

1 2 2 3

2 3 1 4

3 1 5 2

8

aknoip2.in

aknoip2.out

3 2

1 2 1 1

2 3 1 2

-1

【样例解释】

对于样例1:联想过程为1->2->3->1,所需8个单位时间。

对于样例2:无法用联想法AC此题。

【数据范围】

对于40%的数据:n<=1,000,m<=5,000;

对于100%的数据:1<=n<=40,000,1<=m<=100,000,1<=x,y<=1,000。

【备注】

subconscious0的单位时间远小于1秒,因此subconscious0无论如何都能在1秒内AC此题并AKNOIP。subconscious0太强啦!

找一个最小环,刚开始自己想了一个一次扫的方法,就是spfa求前驱,枚举找最小环的方法,但是后来发现错了。

王聿中老师讲了一个非常好的方法,就是将1号点拆成终点和起点,然后因为至少需要经过3个点,1号点外还至少需要经过两个点,所以枚举一排终点,一排起点,

随机跑log n次,根据生日悖论,发现正确率是十分可观的,所以就是SS--S.....T---TT这样子跑就可以了,用rand随机哪些点为T,哪些点为S。

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<cstring>
  6 #include<queue>
  7 #include<map>
  8 using namespace std;
  9 
 10 const int NN=40007,MM=100007,INF=1e9+7;
 11 
 12 int n,m,ans=INF;
 13 int cnt,head[NN],next[MM],rea[MM],val[MM];
 14 int dis[NN],pre[NN];
 15 bool flag[NN],stk=0,boo[NN];
 16 map<int,int>p;
 17 
 18 void add(int u,int v,int fee)
 19 {
 20     cnt++;
 21     next[cnt]=head[u];
 22     head[u]=cnt;
 23     rea[cnt]=v;
 24     val[cnt]=fee;
 25     p[u*40000+v]=fee;
 26 }
 27 void Spfa()
 28 {
 29     for (int i=1;i<=n;i++)
 30     {
 31         flag[i]=0;
 32         dis[i]=INF;
 33     }
 34     flag[1]=1;
 35     dis[1]=0;
 36     queue<int>q;
 37     while(!q.empty()) q.pop();
 38     q.push(1);
 39     while (!q.empty())
 40     {
 41         int u=q.front();
 42         flag[u]=0;
 43         q.pop();
 44         for (int i=head[u];i!=-1;i=next[i])
 45         {
 46             int v=rea[i],fee=val[i];
 47             if (dis[u]+fee<dis[v])
 48             {
 49                 dis[v]=dis[u]+fee;
 50                 pre[v]=u;
 51                 if (flag[v]==0)
 52                 {
 53                     flag[v]==1;
 54                     q.push(v);
 55                 }
 56             }
 57             
 58         }
 59     }
 60 }
 61 void dfs(int num,int fa)
 62 {
 63     boo[num]=1;
 64     for (int i=head[num];i!=-1;i=next[i])
 65     {
 66         int v=rea[i],fee=val[i];
 67         if (num!=1&&boo[v]==0&&p[v*40000+1])
 68         {
 69             stk=1;
 70             ans=min(ans,dis[num]+fee+p[v*40000+1]);
 71         }
 72     }
 73     for (int i=head[num];i!=-1;i=next[i])
 74         if (boo[rea[i]]==0) dfs(rea[i],num);
 75     boo[num]=0;
 76 }
 77 void Solve()
 78 {
 79     dfs(1,-1);
 80     if (stk==0) printf("-1\n");
 81     else printf("%d\n",ans);
 82 }
 83 int main()
 84 {
 85     freopen("aknoip.in","r",stdin);
 86     freopen("aknoip.out","w",stdout);
 87     
 88     cnt=0;
 89     memset(head,-1,sizeof(head));
 90     scanf("%d%d",&n,&m);
 91     int x,y,z1,z2;
 92     for (int i=1;i<=m;i++)
 93     {
 94         scanf("%d%d%d%d",&x,&y,&z1,&z2);
 95         add(x,y,z1);
 96         add(y,x,z2);
 97     }
 98     Spfa();
 99     Solve();
100 }

S,T必须是与1号点相连的点。

 

20170803

标签:pac   需要   pen   front   memset   nod   顺序   span   正整数   

原文地址:http://www.cnblogs.com/fengzhiyuan/p/7283039.html

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