8.13<1>题解

为什么多了个<1>呢,因为要一天两场了,真让人兴奋^_^,才怪

考场想不出来,考后迅速AC,考场上想不到,想到了还否定自己,我以后要是再在考场上想出了贪心,或者二分答案,我一定先打出来,我xwd的flag就立这了

T1

就考了个不知道算什么玩意的东西,想分成联通块,肯定是某个子树,若联通块大小为$d$,只要有$\frac{n}{d}$个子树的大小是$d$的倍数即可,前提是$d$是$n$的因子,先跑出来每颗子树的大小,然后$O(n^2)$$O(\frac{n^2}{2})$$O(logn)$,大概都可过,当然$O(n^2)$可能有点悬

 1 #include<bits/stdc++.h>
 2 #include<iostream>
 3 #include<cstdio>
 4 #define maxn 1000100
 5 using namespace std;
 6 int n,js,ans=2;
 7 int head[maxn],to[maxn*2],xia[maxn*2],size[maxn],pd[maxn];
 8 void add(int x,int y)
 9 {
10     to[++js]=y;  xia[js]=head[x];  head[x]=js;
11 }
12 void dfs(int x)
13 {
14     size[x]=1;  pd[x]=1;
15     for(int i=head[x];i;i=xia[i])
16     {
17         int ls=to[i];
18         if(!pd[ls])  {dfs(ls);  size[x]+=size[ls];}
19     }
20 }
21 int main()
22 {
23     scanf("%d",&n);
24     for(int i=1;i<n;++i)
25     {
26         int u,v;  scanf("%d%d",&u,&v);
27         add(u,v);  add(v,u);
28     }
29     dfs(1);
30     for(int i=2;i<=n/2;++i)
31     {
32         if(n%i)  continue;
33         int jl=0;
34         for(int j=1;j<=n;++j)
35             if(!(size[j]%i))  jl++;
36         if(jl==n/i)  ans++;
37     }
38     printf("%d\n",ans);
39     return 0;
40 }
View Code

T2

考场上想到了二分答案,自己脑子抽抽,觉得自己不对,然后就随便选了一个我觉得对的答案?怕是有毛病,用$check$函数,$check$了一个答案,然后就华丽丽的死了,正解就二分然后$check$就好了,关于枚举断点,只需要在1到1可跳到的最远点之间作出选择就可以了,因为后面的点作为断点和前面某个点做断点,在他这又断开了答案是一样的

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #define maxn 50010
 6 using namespace std;
 7 int n,m,bz,l,r,mj;
 8 int a[maxn*2],q[maxn*2];
 9 inline int read()
10 {
11     int e=0;  char ch=getchar();
12     while(ch<'0'||ch>'9')  ch=getchar();
13     while(ch>='0'&&ch<='9')  {e=(e<<3)+(e<<1)+(ch^48);  ch=getchar();}
14     return e;
15 } 
16 bool check(int x)
17 {
18     mj=upper_bound(a+1,a+2*n+1,x)-a;
19     //mj=n;
20     for(int i=1;i<=mj;++i)
21     {
22         int tot=0,da=0,js=0;
23         int j=i;
24         while(j<=i+n-1)
25         {
26             j=upper_bound(a+1,a+2*n+1,a[j-1]+x)-a;  js++;
27             if(js>m)  break;
28         }
29         if(js<=m)  return 1;
30     }
31     return 0;
32 }
33 int main()
34 {
35     n=read();  m=read();
36     for(int i=1;i<=n;++i)  {q[i]=read();  r+=q[i];  l=max(l,q[i]);  a[i]=q[i]+a[i-1];}
37     for(int i=n+1;i<=2*n;++i)  {q[i]=q[i-n];  a[i]=q[i]+a[i-1];}
38     while(l<r)
39     {
40         int mid=(l+r)>>1;
41         if(check(mid))  r=mid;
42         else  l=mid+1;
43     }
44     printf("%d\n",l);
45     return 0;
46 }
View Code

T3

考场上不知道自己在干什么,打了一个多小时,已经调完了,发现自己思路完全不对,甚至题都没申清的那一刻,心态炸裂,当场不想调,就那样了,实际上就先把能到达的点之间连边,然后把到达敌人的边缩掉,跑最短路记录方案就可以了

  1 //给能跳到的点之间连边
  2 //连边是O(nm)的
  3 //边权为0的缩掉,重边对bfs无影响
  4 //最后的连向终点的边权当作一,给答案减一即可,不然会被缩掉
  5 //跑最短路,记录方案数用bfs实现,SPFA可打
  6 //松弛的时候顺便记录方案
  7 //一个点建8条边,最多2500个点,大概最多20000条边
  8 #include<iostream>
  9 #include<cstring>
 10 #include<cstdio>
 11 #include<queue>
 12 #define int long long
 13 #define maxn 55
 14 #define maxm 41000
 15 #define bh(i,j)  ((i-1)*m+j)
 16 using namespace std;
 17 int n,m,qd,zd,js,j;
 18 int head[maxn*maxn],to[maxm],xia[maxm],w[maxm];
 19 int h[maxn*maxn],t[maxm],x[maxm];//重建之后边权均为1
 20 int v[maxn*maxn],pd[maxn*maxn],pre[maxn*maxn];
 21 int dis[maxn*maxn],tot[maxn*maxn];
 22 int a[maxn][maxn];
 23 void add(int x,int y,int z)
 24 {
 25     to[++js]=y;  xia[js]=head[x];  w[js]=z;  head[x]=js;
 26 }
 27 void Add(int a,int b)
 28 {
 29     t[++j]=b;  x[j]=h[a];  h[a]=j;
 30 }
 31 void sou(int q,int z)
 32 {
 33     v[z]=1;
 34     for(int i=head[z];i;i=xia[i])
 35     {
 36         int ls=to[i];
 37         if(v[ls])  continue;
 38         if(w[i])
 39         {
 40             if(!pd[ls])  {Add(q,ls);  pd[ls]=1;}
 41         }
 42         else  sou(q,ls);
 43     }
 44 }
 45 void SPFA(int u)
 46 {
 47     memset(dis,0x7f,sizeof(dis));
 48     queue <int> s;  dis[u]=0;  tot[u]=1;  v[u]=1;  s.push(u);
 49     while(s.size())
 50     {
 51         int ls=s.front();  s.pop();
 52         for(int i=h[ls];i;i=x[i])
 53         {
 54             if(dis[ls]+1==dis[t[i]])  tot[t[i]]+=tot[ls];
 55             else if(dis[ls]+1<dis[t[i]])
 56             {
 57                 pre[t[i]]=ls;
 58                 dis[t[i]]=dis[ls]+1;
 59                 tot[t[i]]=tot[ls];
 60                 if(!v[t[i]])  {s.push(t[i]);  v[t[i]]=1;}
 61             }
 62         }
 63         v[ls]=0;
 64     }
 65 }
 66 signed main()
 67 {
 68     scanf("%lld%lld",&n,&m);
 69     for(int i=1;i<=n;++i)
 70         for(int j=1;j<=m;++j)
 71         {
 72             scanf("%lld",&a[i][j]);
 73             if(a[i][j]==3)  qd=bh(i,j);
 74             if(a[i][j]==4)  zd=bh(i,j);
 75         }
 76     for(int i=1;i<=n;++i)
 77         for(int j=1;j<=m;++j)
 78         {
 79             if(a[i][j]==2)  continue;
 80             int num=bh(i,j);
 81             if(i+2<=n&&j+1<=m&&a[i+2][j+1]!=2)//i+2 j+1
 82             {
 83                 int pos=bh(i+2,j+1);
 84                 if(a[i+2][j+1]==1)  add(num,pos,0);
 85                 else  add(num,pos,1);
 86             }
 87             if(i+2<=n&&j-1>=1&&a[i+2][j-1]!=2)//i+2 j-1
 88             {
 89                 int pos=bh(i+2,j-1);
 90                 if(a[i+2][j-1]==1)  add(num,pos,0);
 91                 else  add(num,pos,1);
 92             }
 93             if(i-2>=1&&j+1<=m&&a[i-2][j+1]!=2)//i-2 j+1
 94             {
 95                 int pos=bh(i-2,j+1);
 96                 if(a[i-2][j+1]==1)  add(num,pos,0);
 97                 else  add(num,pos,1);
 98             }
 99             if(i-2>=1&&j-1>=1&&a[i-2][j-1]!=2)//i-2 j-1
100             {
101                 int pos=bh(i-2,j-1);
102                 if(a[i-2][j-1]==1)  add(num,pos,0);
103                 else  add(num,pos,1);
104             }
105             if(i+1<=n&&j+2<=m&&a[i+1][j+2]!=2)//i+1 j+2
106             {
107                 int pos=bh(i+1,j+2);
108                 if(a[i+1][j+2]==1)  add(num,pos,0);
109                 else  add(num,pos,1);
110             }
111             if(i+1<=n&&j-2>=1&&a[i+1][j-2]!=2)//i+1 j-2
112             {
113                 int pos=bh(i+1,j-2);
114                 if(a[i+1][j-2]==1)  add(num,pos,0);
115                 else  add(num,pos,1);
116             }
117             if(i-1>=1&&j+2<=m&&a[i-1][j+2]!=2)//i-1 j+2
118             {
119                 int pos=bh(i-1,j+2);
120                 if(a[i-1][j+2]==1)  add(num,pos,0);
121                 else  add(num,pos,1);
122             }
123             if(i-1>=1&&j-2>=1&&a[i-1][j-2]!=2)//i-1 j-2
124             {
125                 int pos=bh(i-1,j-2);
126                 if(a[i-1][j-2]==1)  add(num,pos,0);
127                 else  add(num,pos,1);
128             }
129         }
130     for(int i=1;i<=n;++i)
131         for(int j=1;j<=m;++j)
132         {
133             if(a[i][j]==1||a[i][j]==2)  continue;
134             int num=bh(i,j);  sou(num,num);
135             memset(v,0,sizeof(v));  memset(pd,0,sizeof(pd));
136         }
137     SPFA(qd);
138     if(tot[zd]==0)  printf("-1\n");
139     else printf("%lld\n%lld\n",dis[zd]-1,tot[zd]);
140     return 0;
141 }
View Code

 

posted @ 2019-08-13 17:50  hzoi_X&R  阅读(551)  评论(0编辑  收藏  举报