Codeforces Round #513解题报告(A~E)By cellur925

我是比赛地址

A:Phone Numbers

$Description$:给你一串数字,问你能组成多少开头为8的11位电话号码。

$Sol$:统计8的数量,与$n$%11作比较。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 
 5 using namespace std;
 6 
 7 int n,len,cnt,ans;
 8 char ch[1000];
 9 
10 int main()
11 {
12     scanf("%d",&n);
13     scanf("%s",ch+1);
14     len=strlen(ch+1);
15     for(int i=1;i<=len;i++)
16         if(ch[i]=='8') cnt++;
17     if(!cnt){printf("0");return 0;}
18     ans=min(cnt,n/11);
19     printf("%d\n",ans);
20     return 0;
21 }
A

B:Maximum Sum of Digits

$Description$:定义函数$S$为把这个十进制数各位拆出再加和的值,给定整数$n$,求出和为$n$的两个数的$S$值最大。

$Sol$:我们贪心地想要更多的9,因为这样会创造更多的价值。所以我们构造两个数,一个数比$n$小一位,但都是9,再用$n$减去它得到另一个数。

 1 #include<cstdio>
 2 #include<algorithm>
 3 
 4 using namespace std;
 5 typedef long long ll;
 6 
 7 int len;
 8 ll n,ans,odd;
 9 
10 ll ksm(ll a,ll b)
11 {
12     ll pos=1;
13     while(b)
14     {
15         if(b&1) pos=pos*a;
16         b>>=1;
17         a=a*a;
18     }
19     return pos;
20 }
21 
22 int main()
23 {
24     scanf("%I64d",&n);
25     ll tmp=n,hu=n;
26     while(tmp)
27     {
28         tmp/=10;
29         len++;
30     }
31     ans+=(len-1)*9;
32     for(int i=len-2;i>=0;i--)
33         odd+=ksm(10,i)*9;
34     hu-=odd;
35     while(hu)
36     {
37         ans+=hu%10;
38         hu/=10;
39     }
40     printf("%I64d",ans);
41     return 0;
42 }
B

C:Maximum Subrectangle

$Description$:给出一矩阵,求出一子矩阵,使得矩阵内元素的权值和<=$X$,并最大化矩阵的面积。

$Sol$:开始想出的是$O$($n^4$)算法,搞一个二维前缀和,再枚举矩形右下断点及长宽。(注意,不是正方形)。正解:考虑矩阵的构造方式:ci,j=ai*bj。那么我们分别先求出$a$,$b$数组的前缀和,再用$O$($n^2$)的时间预处理出各数组长度为$len$时的最小连续子段和。之后枚举这个$len$,在满足权值<=$X$的情况下最大化矩阵的面积。这部分复杂度也是$O$($n^2$)的。泥珂能会质疑这个算法,但是它其实是满足结合/分配律的。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define maxn 2090
 5 
 6 using namespace std;
 7 typedef long long ll;
 8 
 9 int n,m;
10 ll X;
11 ll ans,lena[maxn],lenb[maxn],suma[maxn],sumb[maxn];
12 
13 ll lmax(ll a,ll b)
14 {
15     if(a>b) return a;
16     return b;
17 }
18 
19 int main()
20 {
21     scanf("%d%d",&n,&m);
22     for(int i=1;i<=n;i++)
23     {
24         ll x=0;
25         scanf("%I64d",&x);
26         suma[i]=suma[i-1]+x;
27     } 
28     for(int i=1;i<=m;i++)
29     {
30         ll x=0;
31         scanf("%I64d",&x);
32         sumb[i]=sumb[i-1]+x;
33     }
34     scanf("%I64d",&X);
35     memset(lena,0x3f,sizeof(lena));
36     memset(lenb,0x3f,sizeof(lenb));
37     for(int len=1;len<=n;len++)
38         for(int i=1;i+len-1<=n;i++)
39             lena[len]=min(lena[len],suma[i+len-1]-suma[i-1]);
40     for(int len=1;len<=m;len++)
41         for(int i=1;i+len-1<=m;i++)
42             lenb[len]=min(lenb[len],sumb[i+len-1]-sumb[i-1]);
43     for(int i=1;i<=n;i++)
44         for(int j=1;j<=m;j++)
45             if(1ll*lena[i]*lenb[j]<=X)
46                 ans=lmax(ans,i*j);
47     printf("%I64d",ans);
48     return 0;
49 }
C

D:Social Circles

$Description$:有很多人在一起坐在圆桌边吃饭,椅子上有一个人或没有,但是他们都很羞涩,每个人左边和右边必须至少留出一定的空位,求最多安排多少椅子。

$Sol$:从这题开始自闭,但没想到是大贪心。将$l$与$r$数组排序,对于每个位置$i$,将二者中的最大值累加进答案。这是我们需要留空位的椅子。最后因为每个人都要坐在椅子上,所以答案再加上人数。

 1 #include<cstdio>
 2 #include<algorithm>
 3 
 4 using namespace std;
 5 typedef long long ll;
 6 
 7 int n;
 8 int l[100090],r[100090];
 9 ll ans;
10 
11 int main()
12 {
13     scanf("%d",&n);
14     for(int i=1;i<=n;i++)
15         scanf("%d%d",&l[i],&r[i]);
16     sort(l+1,l+1+n);
17     sort(r+1,r+1+n);
18     for(int i=1;i<=n;i++) ans+=max(l[i],r[i]);
19     ans+=n;
20     printf("%I64d\n",ans); 
21     return 0;
22 }
D

E:Sergey and Subway

$Description$:给定一棵树,每条边权值为1,当任意两点距离为2时可在他们之间连一条新边。求出所有点对的最短路之和。

$Sol$:考虑每条边的答案的贡献。首先并且不考虑新边,求出所有点对的距离:$size[v]$*($n$-$size[v]$)。而经过加新边的操作后,原来距离为偶数的点对距离/2,奇数点对距离/2+1。而我们可以通过黑白染色后黑/白点的数目统计出奇数距离的点对数目。(这部分引用自skylee,侵删。)

$Warning$:今天所有的题目都要注意开$longlong$,尤其在一些不容易被看到的细节,乘着乘着就炸了。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define maxn 200090
 4 
 5 using namespace std;
 6 typedef long long ll;
 7 
 8 int n,tot;
 9 ll ans,col[10];
10 int head[maxn],d[maxn],size[maxn];
11 struct node{
12     int to,next;
13 }edge[maxn*2];
14 
15 void add(int x,int y)
16 {
17     edge[++tot].to=y;
18     edge[tot].next=head[x];
19     head[x]=tot;
20 }
21 
22 void dfs1(int u,int fa,int dep)
23 {
24     d[u]=dep;
25     size[u]=1;
26     for(int i=head[u];i;i=edge[i].next)
27     {
28         int v=edge[i].to;
29         if(v==fa) continue;
30         dfs1(v,u,dep+1);
31         size[u]+=size[v];
32     }
33 }
34 
35 void dfs2(int u,int fa)
36 {
37     for(int i=head[u];i;i=edge[i].next)
38     {
39         int v=edge[i].to;
40         if(v==fa) continue;
41         ans+=1ll*(n-size[v])*size[v];
42         dfs2(v,u);
43     }
44 }
45 
46 int main()
47 {
48     scanf("%d",&n);
49     for(int i=1;i<=n-1;i++)
50     {
51         int x=0,y=0;
52         scanf("%d%d",&x,&y);
53         add(x,y),add(y,x);
54     }
55     dfs1(1,0,1);
56     for(int i=1;i<=n;i++) ++col[d[i]%2];
57     dfs2(1,0);
58     ans=(ans+(col[1]*col[0]))>>1;
59     printf("%I64d",ans);
60     return 0;
61 }
E

自己做出了A&B,在LAdalao的指点下写了第三题。$Codeforces$真是一款紧张刺激又烧脑的游戏,我喜欢!(雾)

 

posted @ 2018-10-04 23:24  cellur925&Chemist  阅读(229)  评论(0编辑  收藏  举报