CONTEST36 小Z的模拟赛(2)

A.小Z的可恶路障

题目:http://www.luogu.org/problem/show?pid=U126

题解:暴力也可以过吧。我为了保险先求了一次最短路,然后枚举这条最短路上的所有边。。。

代码:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<iostream>
 7 #include<vector>
 8 #include<map>
 9 #include<set>
10 #include<queue>
11 #include<string>
12 #define inf 1000000000
13 #define maxm 100000
14 #define eps 1e-10
15 #define ll long long
16 #define pa pair<int,int>
17 #define for0(i,n) for(int i=0;i<=(n);i++)
18 #define for1(i,n) for(int i=1;i<=(n);i++)
19 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
20 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
21 #define mod 1000000007
22 using namespace std;
23 inline int read()
24 {
25     int x=0,f=1;char ch=getchar();
26     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
27     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
28     return x*f;
29 }
30 struct edge{int go,next,w,from;}e[2*maxm];
31 int n,m,tot=1,q[maxm],d[maxm],head[maxm],pre[maxm];
32 bool v[maxm],can[maxm];
33 void ins(int x,int y,int z)
34 {
35     e[++tot].go=y;e[tot].from=x;e[tot].w=z;e[tot].next=head[x];head[x]=tot;
36 }
37 void insert(int x,int y,int z)
38 {
39     ins(x,y,z);ins(y,x,z);
40 }
41 void spfa()
42 {
43     for(int i=1;i<=n;++i) d[i]=inf;
44     memset(v,0,sizeof(v));
45     int l=0,r=1,x,y;q[1]=1;d[1]=0;
46     while(l!=r)
47     {
48         x=q[++l];if(l==maxm-1)l=0;v[x]=0;
49         for(int i=head[x];i;i=e[i].next)
50          if(d[x]+e[i].w<d[y=e[i].go])
51          {
52              d[y]=d[x]+e[i].w;
53              pre[y]=i;
54              if(!v[y]){v[y]=1;q[++r]=y;if(r==maxm-1)r=0;}
55          }
56     }
57 }
58 int main()
59 {
60     freopen("input.txt","r",stdin);
61     freopen("output.txt","w",stdout);
62     n=read();m=read();int x,y,z;
63     for1(i,m)x=read(),y=read(),z=read(),insert(x,y,z);
64     spfa();
65     for(int i=pre[n];i;i=pre[e[i].from])can[i]=1;
66     int ans=0,tmp=d[n];
67     for1(i,tot)
68     if(can[i])
69     {
70         e[i].w<<=1;
71         e[i^1].w<<=1;
72         spfa();
73         ans=max(ans,d[n]-tmp);
74         e[i].w>>=1;
75         e[i^1].w>>=1;
76     }
77     printf("%d
",ans);
78     return 0;
79 }
View Code

B.小Z的游戏分队

题目:http://www.luogu.org/problem/show?pid=U127

题解:这题我做的比较满意,说一下我的做法:

         首先i 不愿意与 j 在一组,那么我们就merge(i,j+n) merge(j+n,i) (做过食物链、关押罪犯的都知道什么意思吧。。。)

         然后执行完之后整个图就分为了好多个块块,有些块之间有边相连,代表这两块一定不能在同一组里。

         当然一个块最多只会和一个块相连,否则这两个块一定已经被缩成了一个块

         然后怎么做呢?类似与搭建双塔,我们可以用一个二维可行性背包DP,当然应为总人数是确定的,所以可以缩成1维

         状态如何转移呢?

         

 1 f[0]=1;
 2      for1(i,n)
 3      if(s[i])
 4      {
 5       if(can[i])
 6        {
 7          for3(j,n-s[i],0)
 8           if(f[j])f[j+s[i]]=1;
 9        }
10       else if(b[i])
11        {
12          for3(j,n,0)
13          if(f[j])
14          {
15              f[j]=0;
16              if(j+s[i]<=n)f[j+s[i]]=1;
17              if(j+s[b[i]]<=n)f[j+s[b[i]]]=1;
18          }
19        }
20      }

        应该很清楚了吧。如果 i 块没有边与其他块相连,那么它可以选择加进 a 组,或者不加进 a 组

        否则  它与它相连的块要么一个在 a 组,要么 另一个在 a 组。

        最后统计一下就ok了。

代码:

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<iostream>
  7 #include<vector>
  8 #include<map>
  9 #include<set>
 10 #include<queue>
 11 #include<string>
 12 #define inf 1000000000
 13 #define maxn 100000
 14 #define maxm 500+100
 15 #define eps 1e-10
 16 #define ll long long
 17 #define pa pair<int,int>
 18 #define for0(i,n) for(int i=0;i<=(n);i++)
 19 #define for1(i,n) for(int i=1;i<=(n);i++)
 20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
 21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
 22 #define mod 1000000007
 23 using namespace std;
 24 inline int read()
 25 {
 26     int x=0,f=1;char ch=getchar();
 27     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 28     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
 29     return x*f;
 30 }
 31 int n,fa[maxn],a[maxn],b[maxn],s[maxn];
 32 bool can[maxn],f[maxn];
 33 inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
 34 inline void merge(int x,int y)
 35 {
 36     int xx=find(x),yy=find(y);
 37     if(xx!=yy)fa[yy]=xx;
 38 }
 39 int main()
 40 {
 41     freopen("input.txt","r",stdin);
 42     freopen("output.txt","w",stdout);
 43     n=read();
 44     for1(i,n*2)fa[i]=i;
 45     for1(i,n)
 46     {
 47         int x=read();
 48         while(x){can[x]=1;x=read();};
 49         for1(j,n)
 50         {
 51             if(!can[j]&&j!=i)
 52              {
 53                  if(find(j)==find(i)||find(j+n)==find(i+n))
 54                  {printf("No solution
");return 0;}
 55                 merge(i,j+n);
 56                 merge(j,i+n);
 57              }
 58             can[j]=0;
 59         }
 60     }
 61     for1(i,n)if(find(i)==find(i+n)){printf("No solution
");return 0;}
 62     for1(i,n)s[find(i)]++;
 63     for1(i,n)can[i]=1;
 64     for1(i,n)
 65      for1(j,n)
 66       if(find(i)==find(j+n))
 67        {
 68            int x=find(i),y=find(j);
 69            b[min(x,y)]=max(x,y);
 70            can[x]=can[y]=0;
 71        }
 72      f[0]=1;
 73      for1(i,n)
 74      if(s[i])
 75      {
 76       if(can[i])
 77        {
 78          for3(j,n-s[i],0)
 79           if(f[j])f[j+s[i]]=1;
 80        }
 81       else if(b[i])
 82        {
 83          for3(j,n,0)
 84          if(f[j])
 85          {
 86              f[j]=0;
 87              if(j+s[i]<=n)f[j+s[i]]=1;
 88              if(j+s[b[i]]<=n)f[j+s[b[i]]]=1;
 89          }
 90        }
 91      }
 92      int ans=n,x=0,y=n;
 93      for1(i,n)
 94      if(f[i])
 95      {
 96          int j=n-i;
 97          if(abs(i-j)<ans)ans=abs(i-j),x=i,y=j;
 98      }
 99      printf("%d %d
",min(x,y),max(x,y));
100     return 0;
101 }
View Code

C.小Z的神奇数列

题目:http://www.luogu.org/problem/show?pid=U129

题解:SXBK的出题人,硬是把我的线段树卡到和暴力一个分T_T

        线段树的做法应该是显然的吧,先将数组排序,然后每次二分到要删的位置,线段树单点修改一下。

        不知道出题人的标程是什么神奇的做法。

代码:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<iostream>
 7 #include<vector>
 8 #include<map>
 9 #include<set>
10 #include<queue>
11 #include<string>
12 #define inf 1000000000
13 #define maxn 1000000+10000
14 #define maxm 5000000+10000
15 #define eps 1e-10
16 #define ll long long
17 #define pa pair<int,int>
18 #define for0(i,n) for(int i=0;i<=(n);i++)
19 #define for1(i,n) for(int i=1;i<=(n);i++)
20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
22 #define mod 317847191
23 using namespace std;
24 inline int read()
25 {
26     int x=0,f=1;char ch=getchar();
27     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
28     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
29     return x*f;
30 }
31 int n,m,a[maxn],mx[maxm],mi[maxm],ret[maxm];
32 bool b[maxn];
33 int find(int x)
34 {
35     int l=1,r=n,mid;
36     while(l<=r)
37     {
38         mid=(l+r)>>1;
39         if(a[mid]>x||(a[mid]==x&&b[mid]))r=mid-1;
40         else l=mid+1;
41     }
42     b[l]=0;
43     return l;
44 }
45 inline void pushup(int k)
46 {
47     mx[k]=max(mx[k<<1],mx[k<<1|1]);
48     mi[k]=min(mi[k<<1],mi[k<<1|1]);
49     ll tmp=ret[k<<1];
50     tmp=(tmp*ret[k<<1|1])%mod;
51     ret[k]=tmp;
52 }
53 inline void build(int k,int l,int r)
54 {
55     int mid=(l+r)>>1;
56     if(l==r){mx[k]=mi[k]=ret[k]=a[l];return;}
57     build(k<<1,l,mid);build(k<<1|1,mid+1,r);
58     pushup(k);
59 }
60 inline void del(int k,int l,int r,int x)
61 {
62     int mid=(l+r)>>1;
63     if(l==r){mx[k]=-inf;mi[k]=inf;ret[k]=1;return;}
64     if(x<=mid)del(k<<1,l,mid,x);else del(k<<1|1,mid+1,r,x);
65     pushup(k);
66 }
67 int main()
68 {
69     freopen("input.txt","r",stdin);
70     freopen("output.txt","w",stdout);
71     n=read();m=read();
72     for1(i,n)a[i]=read();
73     sort(a+1,a+n+1);
74     for1(i,n)b[i]=1;
75     build(1,1,n);
76     ll ans,x,y;
77     while(m--)
78     {
79         char ch[2];
80         scanf("%s",ch);
81         if(ch[0]=='D')del(1,1,n,find(read()));
82         else if(ch[0]=='B')printf("%d
",mx[1]);
83         else if(ch[0]=='S')printf("%d
",mi[1]);
84         else if(ch[0]=='M')
85         {
86             for(ans=1,x=mx[1],y=mi[1];y;y>>=1,x=(x*x)%mod)
87              if(y&1)ans=(ans*x)%mod;
88             printf("%d
",ans);
89         }
90         else printf("%d
",ret[1]);
91     }
92     return 0;
93 }
View Code

D.小Z的迷之阶梯

题目:http://www.luogu.org/problem/show?pid=U130

题解:出题人的声明就是在告诉我们这是道大水题吧。。。

        n=200的数据范围很容易让我们想到n^3的算法,枚举上一个点o(n),枚举从该点向下退的次数o(n),

        状态数o(n),n^3水过。。。

代码:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<iostream>
 7 #include<vector>
 8 #include<map>
 9 #include<set>
10 #include<queue>
11 #include<string>
12 #define inf 1000000000
13 #define maxn 100000
14 #define maxm 500+100
15 #define eps 1e-10
16 #define ll long long
17 #define pa pair<int,int>
18 #define for0(i,n) for(int i=0;i<=(n);i++)
19 #define for1(i,n) for(int i=1;i<=(n);i++)
20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
22 #define mod 1000000007
23 using namespace std;
24 inline int read()
25 {
26     int x=0,f=1;char ch=getchar();
27     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
28     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
29     return x*f;
30 }
31 int n,a[maxn],f[maxn];
32 int main()
33 {
34     freopen("input.txt","r",stdin);
35     freopen("output.txt","w",stdout);
36     n=read();
37     for1(i,n)a[i]=read();
38     f[1]=0;
39     for2(i,2,n)f[i]=inf;
40     for2(i,2,n)
41      for1(j,i-1)
42       for0(k,j-1)
43        if(a[j-k]+(1<<k)>=a[i])
44         f[i]=min(f[i],f[j]+k+1);
45     printf("%d
",f[n]==inf?-1:f[n]);
46     return 0;
47 }
View Code

   

原文地址:https://www.cnblogs.com/zyfzyf/p/4003484.html