Educational Codeforces Round 45 (Rated for Div. 2)

D.http://codeforces.com/contest/990/problem/D

题意:给定n,a,b分别表示一个无向图中点的数量,这个图的连通块数量为a,这个图的补图的连通块的数量为b,输出n*n的邻接矩阵((i,j)为1表示点i和点j有边相连,(i,j)为0表示点i和点j无边相连)

分析:构造题,分类讨论。首先易得无论图中有多少点,原图和补图中至少有一个图的连通块数量为1。

情况1:若a和b中有一个不为1,那么我们可以构造出相应的图(可以考虑编号为1的点和其他点相连,剩下的点单独作为一个连通块)

情况2:a==1&&b==1&&n>=4 此时我们需要构造链状的结构

情况3:a==1&&b==1&&1<n<4此时不存在这样的情况

情况4:a==1&&b==1&&n==1此时单独的一个点不连任何的边可以满足条件

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn=1010;
 6 int dp[maxn][maxn];
 7 
 8 int main()
 9 {
10     int n,a,b,x,y,z,i,j,k;
11     bool flag;
12     while ( scanf("%d%d%d",&n,&a,&b)!=EOF )
13     {
14         flag=true;
15         if ( a!=1 && b!=1 )
16         {
17             printf("NO\n");
18             continue;
19         }
20         memset(dp,0,sizeof(dp));
21         if ( a!=1 )
22         {
23             for ( i=2;i<=n-a+1;i++ )
24             {
25                 dp[1][i]=1;
26             }
27             for ( i=1;i<=n;i++ )
28             {
29                 for ( j=1;j<i;j++ ) dp[i][j]=dp[j][i];
30             }
31         }
32         if ( b!=1 )
33         {
34             for ( i=2;i<=n-b+1;i++ )
35             {
36                 dp[1][i]=1;
37             }
38             for ( i=1;i<=n;i++ )
39             {
40                 for ( j=1;j<i;j++ ) dp[i][j]=dp[j][i];
41             }
42             for ( i=1;i<=n;i++ )
43             {
44                 for ( j=1;j<=n;j++ )
45                 {
46                     if ( i==j ) continue;
47                     dp[i][j]^=1;
48                 }
49             }
50         }
51         if ( a==1 && b==1 )
52         {
53             if ( n>=4 )
54             {
55                 for ( i=1;i<n-a+1;i++ )
56                 {
57                     dp[i][i+1]=1;
58                 }
59                 for ( i=1;i<=n;i++ )
60                 {
61                     for ( j=1;j<i;j++ ) dp[i][j]=dp[j][i];
62                 }    
63             }    
64             else if ( n>1 ) flag=false;
65         }
66         if ( !flag ) printf("NO\n");
67         else
68         {
69             printf("YES\n");
70             for ( i=1;i<=n;i++ )
71             {
72                 for ( j=1;j<=n;j++ ) printf("%d",dp[i][j]);
73                 printf("\n");
74             }
75         }
76     }
77     return 0;
78 }
D

E.http://codeforces.com/contest/990/problem/E

题意:有一段[0,n]的线段,现在可以在0,1……n-1放置灯笼。现在给出m个不能放灯笼的点。给出k种灯笼,第i种灯笼照亮的范围为i(即:若当前的点在x,可以照亮[x,x+i-1]这个范围),费用为val[i]。现在想要用一种类型的灯笼使[0,n]这段全部照亮所需要的最小费用是多少

分析:采用预处理+暴力的方式(复杂度为nlogn)。首先预处理出若点x不能放灯笼,那么[0,x)中能放灯笼的位置中的横(x)坐标最大是多少。然后计算出每种灯笼想要照亮[0,n]这段所需要的费用,取最小值即可

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 typedef long long ll;
 6 const int maxn=1e6+10;
 7 const ll inf=1e18;
 8 int n,m,k,lt[maxn],cost[maxn];
 9 bool vis[maxn];
10 
11 ll solve(int v)
12 {
13     int now=0;
14     ll cnt=0;
15     while ( true )
16     {
17         cnt++;
18         now+=v;
19         if ( now>=n ) return cnt;
20         if ( lt[now]==now-v ) return -1;
21         now=lt[now];
22     }
23 }
24 
25 int main()
26 {
27     int i,j,x;
28     ll ans,val;
29     while ( scanf("%d%d%d",&n,&m,&k)!=EOF )
30     {
31         memset(vis,false,sizeof(vis));
32         for ( i=1;i<=m;i++ )
33         {
34             scanf("%d",&x);
35             vis[x]=true;
36         }
37         for ( i=1;i<=k;i++ ) scanf("%d",&cost[i]);
38         if ( vis[0] ) 
39         {
40             printf("-1\n");
41             continue;
42         }
43         for ( i=0;i<n;i++ )
44         {
45             if ( vis[i] ) lt[i]=lt[i-1];
46             else lt[i]=i;
47         }
48         ans=inf;
49         for ( i=1;i<=k;i++ )
50         {
51             val=solve(i);
52             if ( val!=-1 ) ans=min(ans,val*cost[i]);
53         }
54         if ( ans==inf ) printf("-1\n");
55         else printf("%lld\n",ans);
56     }
57     return 0;
58 }
E

猜你喜欢

转载自www.cnblogs.com/HDUjackyan/p/9169033.html