10.18 模拟赛

第一次160太不像话了

第二题蛇皮错误并查集f[x]=find(f[x])写错了

改完之后250 mmp

T1:

环形消灭虫子

思路:

首先可以想到枚举起点然后dp消灭虫子 复杂度n2

然后我想到了一个蛇皮优化

因为取到的点是不可能连在一起的

所以我们的枚举有很多是重复的

只需要枚举相邻的任意两个点就可以在它为起点的消灭虫子的答案中得到最优解

因为我们的终点必定有一个是不会被取到的

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<queue>
 8 #include<vector>
 9 #include<set>
10 #include<stack>
11 #define inf 2147483611
12 #define ll long long
13 #define MAXN 152550
14 using namespace std;
15 inline int read()
16 {
17     int x=0,f=1;
18     char ch=getchar();
19     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
20     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
21     return x*f;
22 }
23 int n,a[MAXN];
24 ll dp[MAXN][2],ans;
25 int main()
26 {
27     freopen("rob.in","r",stdin);
28     freopen("rob.out","w",stdout);
29     n=read();
30     for(int i=0;i<n;i++) a[i]=read();
31     for(int i=0;i<2;i++)
32     {
33         memset(dp,0,sizeof(dp));
34         for(int j=0;j<n;j++)
35         {
36             dp[(i+j)%n][0]=max(dp[(j-1+i+n)%n][0],dp[(i+n+j-1)%n][1]);
37             dp[(i+j)%n][1]=dp[(j-1+i+n)%n][0]+a[(i+j)%n];
38         }
39         ans=max(ans,dp[(i+n-1)%n][0]);
40     }
41     printf("%lld",ans);
42 }
View Code

 T2:

有一个无向连通图

删去一些边使得这些点恰好为两个连通块

思路:

我们可以找到一个最小生成树

然后砍掉树里最大的边

树里剩下的边权之和即为答案

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<queue>
 8 #include<vector>
 9 #include<set>
10 #include<stack>
11 #define inf 2147483611
12 #define ll long long
13 #define MAXN 152550
14 using namespace std;
15 inline int read()
16 {
17     int x=0,f=1;
18     char ch=getchar();
19     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
20     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
21     return x*f;
22 }
23 struct data
24 {
25     int from,to,val;
26     bool operator < (const data &a) const
27     {
28         return val<a.val;
29     }
30 }edge[MAXN];
31 int n,m,cnt,f[MAXN];
32 void add(int u,int v,int w) {edge[++cnt].from=u,edge[cnt].to=v,edge[cnt].val=w;}
33 int find(int x) {return x==f[x]?x:f[x]=find(f[x]);}
34 bool ok(int a,int b)
35 {
36     int fa=find(a),fb=find(b);
37     if(fa==fb) return 1;
38     else {f[fa]=fb;return 0;}
39 }
40 ll kruskal()
41 {
42     int tot=0;ll res=0;
43     for(int i=1;i<=cnt;i++)
44     {
45         if(tot==n-2) break;
46         if(!ok(edge[i].from,edge[i].to)) {tot++;res+=edge[i].val;}
47     }
48     return res;
49 }
50 int main()
51 {
52     freopen("destroy.in","r",stdin);
53     freopen("destroy.out","w",stdout);
54     n=read(),m=read();
55     int a,b,c;
56     for(int i=1;i<=n;i++) f[i]=i;
57     while(m--)
58     {
59         a=read(),b=read(),c=read();
60         add(a,b,c);
61     }
62     sort(edge+1,edge+cnt+1);
63     printf("%lld",kruskal());
64 }
View Code

T3:

给一些数,求有多少种排列使他们满足A[i - 1] + A[i + 1] ≥ 2 × A[i] (2<=i<n)

思路:

(第一次不会直接上全排列暴力)  

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<queue>
 8 #include<vector>
 9 #include<set>
10 #include<stack>
11 #define inf 2147483611
12 #define ll long long
13 #define MAXN 45
14 #define MOD 998244353
15 using namespace std;
16 inline int read()
17 {
18     int x=0,f=1;
19     char ch=getchar();
20     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
21     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
22     return x*f;
23 }
24 int n,ans;
25 struct data
26 {
27     int pos,val;
28     bool operator < (const data &a) const
29     {
30         return val<a.val||(val==a.val&&pos<a.pos);
31     }
32 }a[MAXN];
33 int main()
34 {
35     freopen("permutation.in","r",stdin);
36     freopen("permutation.out","w",stdout);
37     n=read();
38     for(int i=1;i<=n;i++) a[i].val=read(),a[i].pos=i;
39     sort(a+1,a+n+1);
40     int i;
41     while(1)
42     {
43         for(i=2;i<n;i++) if(a[i-1].val+a[i+1].val<2*a[i].val) break;
44         if(i==n) ans++;
45         ans%=MOD;
46         if(!next_permutation(a+1,a+n+1)) break;
47     }
48     printf("%d",ans);
49 }
View Code

正解:

可以注意到n非常小

我们可以简化一下条件a[i] - a[i - 1] ≤ a[i + 1] - a[i]

然后对a数组排序

这样的话,我们需要把最小值放在数列的中间,然后对于下一个数我们只能放在它的两边

因此我们设一个dp四维数组 表示左边两个数为ai aj ak al 的符合题意的序列的个数

但是最小值可能有很多个

所以我们需要统计一下最小值的个数,然后对于答案*最小值的个数

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<queue>
 8 #include<vector>
 9 #include<set>
10 #include<stack>
11 #define inf 2147483611
12 #define ll long long
13 #define MAXN 45
14 #define MOD 998244353
15 using namespace std;
16 inline int read()
17 {
18     int x=0,f=1;
19     char ch=getchar();
20     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
21     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
22     return x*f;
23 }
24 int n,a[MAXN],cnt,tmp;
25 ll dp[MAXN][MAXN][MAXN][MAXN],m,ans;
26 int main()
27 {
28     freopen("permutation.in","r",stdin);
29     freopen("permutation.out","w",stdout);
30     n=read();
31     for(int i=1;i<=n;i++) a[i]=read();
32     sort(a+1,a+n+1);
33     m=1;
34     for(int i=1;i<=n;i++) if(a[i]==a[1]) {m=(m*i)%MOD;cnt++;}
35     for(int i=2;i<=n-cnt+1;i++) a[i]=a[i+cnt-1];
36     a[0]=a[1],dp[1][0][1][0]=1;
37     n=n-cnt+1;
38     for(int i=1;i<=n;i++)
39         for(int j=0;j<n;j++)
40             for(int k=1;k<=n;k++)
41                 for(int l=0;l<n;l++)
42                 {
43                     if(!dp[i][j][k][l]) continue;
44                     tmp=max(i,k)+1;
45                     if(tmp==n+1) {(ans+=dp[i][j][k][l])%=MOD;continue;}
46                     if(a[tmp]-a[i]>=a[i]-a[j]) (dp[tmp][i][k][l]+=dp[i][j][k][l])%=MOD;
47                     if(a[tmp]-a[k]>=a[k]-a[l]) (dp[i][j][tmp][k]+=dp[i][j][k][l])%=MOD;
48                 }
49     (ans*=m)%=MOD;
50     printf("%d",ans);
51 }
View Code
posted @ 2017-10-18 20:05  jack_yyc  阅读(151)  评论(0编辑  收藏  举报