20170803
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20170803相关的知识,希望对你有一定的参考价值。
今天早上依旧兴奋地考了一早上,一位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的主要内容,如果未能解决你的问题,请参考以下文章