Codeforces Round #513解题报告(A~E)By cellur925
$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 }
$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 }
$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 }
$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 }
$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 }
自己做出了A&B,在LAdalao的指点下写了第三题。$Codeforces$真是一款紧张刺激又烧脑的游戏,我喜欢!(雾)