总结
好弱呀…两场才勉强上蓝qwq…
这场比赛再次告诉我们——一定要看样例解释…否则很容易做自闭的.
A.Phone Numbers
00:05(0)
模拟
很不愉快的开始…
打完代码发现CodeBlocks和dev都崩溃了,很不愉快的再打了一遍。
看完题后发现只要长度和8
的个数足够多就行。
因此输出min(n/11,cnt8)min(n/11,cnt_8)min(n/11,cnt8)即可。
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
#define MAXN 100
char s[MAXN+5];
int n,cnt,p;
int main()
{
scanf("%d",&n);
scanf("%s",s+1);
p=n;
for(int i=1;i<=n;i++)
if(s[i]=='8')
{
if(p-11>=0){cnt++;p-=11;}//当时傻了...
}
printf("%d",cnt);
}
B.Maximum Sum of Digits
00:17(0)
贪心+结论
要求数SSS拆出来的两个数aaa,bbb各数位之和的最大值。
显然,我们要充分利用进位的性质。
设Digit(x)Digit(x)Digit(x)表示数xxx有多少位。
令a≥ba≥ba≥b,若要进位,则一定满足Digit(S)=Digit(a)+1Digit(S)=Digit(a)+1Digit(S)=Digit(a)+1。
考虑aaa应该如何取值。若要满足所有SSS都可以进位,显然aaa的每一位都应该为9
。
可以证明这是最优的(用反证法).
模拟并输出aaa与bbb各位数的和即可。
(代码有点麻烦)
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
#define MAXN 100
#define LL long long
LL n,N,D,A,B,k;
int main()
{
scanf("%lld",&n);
N=n;
if(n<10){printf("%lld",n);return 0;}
while(n)
{
n/=10;
B+=9;
k*=10;
k+=9;
}
k/=10;B-=9;
N-=k;
while(N)
{
A+=N%10;
N/=10;
}
printf("%lld",A+B);
}
C.Maximum Subrectangle
01:08(-2)
预处理
一道坑题…
考试的时候一眼二维滑窗,结果…
光速WA…后来发现只需要预处理就好了。
首先我们可以注意到的是对于矩阵(ax,ay),(bx,by)(a_x,a_y),(b_x,b_y)(ax,ay),(bx,by) (ax≤bx且ay≤by)(a_x≤b_x且a_y≤b_y)(ax≤bx且ay≤by)
矩阵内的和为∑i=axbxAi∗∑j=aybyBj\sum_{i=a_x}^{b_x}{A_i}*\sum_{j=a_y}^{b_y}{B_j}∑i=axbxAi∗∑j=aybyBj(可以展开之后看看)。
因此我们应该对AAA,BBB数组分别求前缀和。
考虑如何在AAA,BBB数组分别选取一个区间使其和的乘积小于xxx。
注意我们求的是矩形面积最大,容易发现答案只要求了选取的两区间的长度。
我们可以贪心地想,对于两个数组,分别预处理长度为LLL时所取到的最小的区间和。
再n2n^2n2枚举两数组区间长度,若≤x≤x≤x则计入答案即可。
注意要开long long
时间复杂度:O(n2)O(n^2)O(n2)
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
#define MAXN 2000
#define LL long long
#define INF 1000000000
LL Mina[MAXN+5],Minb[MAXN+5];
LL a[MAXN+5],b[MAXN+5];
LL Sa[MAXN+5],Sb[MAXN+5];
LL x,ans;
int n,m;
int main()
{
scanf("%d%d",&n,&m);
ans=0;
for(int i=1;i<=n;i++)
{scanf("%lld",&a[i]);Sa[i]=Sa[i-1]+a[i];}
for(int i=1;i<=m;i++)
{scanf("%lld",&b[i]);Sb[i]=Sb[i-1]+b[i];}
scanf("%lld",&x);
for(int L=1;L<=n;L++)
{
Mina[L]=INF;
for(int i=L;i<=n;i++)
Mina[L]=min(Mina[L],Sa[i]-Sa[i-L]);
}
for(int L=1;L<=m;L++)
{
Minb[L]=INF;
for(int i=L;i<=m;i++)
Minb[L]=min(Minb[L],Sb[i]-Sb[i-L]);
}
for(int A=1;A<=n;A++)
for(int B=1;B<=m;B++)
if(Mina[A]*Minb[B]<=x)ans=max(ans,(LL)A*B);
printf("%lld",ans);
}
D.Social Circles
02:00(-1)
贪心+构造
本来以为C题已经够毒瘤了…结果这题更毒…
看完题以为只能用一个圈…打完代码之后才发现样例二都过不了…
再一次擦亮自己的狗眼…
如果可以围无限个圈的话,这题就是道水题了…
将问题抽象成一个合并问题,那么我们每次合并人iii,jjj的代价就是max(ri,lj)max(r_i,l_j)max(ri,lj)。
那么我们的目标就是找到一种合并方式,使∑max(ri,lj)\sum max(r_i,l_j)∑max(ri,lj)的值最小。
注意到在所有lll,rrr中的最大值被算进最终答案的情况是无法改变的,那么我们的目标就是让比它略小的值不被算进最终答案里,也就是让最大值与与它接近的值合并。
现在我们来设计这个算法:
对于第一次操作,我们先将拥有两个数组最大值的人拿出来。
第二次,我们将次大的值拿出来。
若与上一个值的方向相反,则说明我们可以将这两个值合并起来,代价为max(ri,lj)max(r_i,l_j)max(ri,lj)。
例如我们第一次拿出来的是lil_ili,第二次是rjr_jrj,方向相反,我们就可以合并它。
若方向不相反,则我们就将其拿出,另外构造一个环。
接下来不断进行如上操作…
然而这个算法未免有点麻烦…
考虑简化这个算法。
注意到最大的值总要等到最大的与它方向相反的值出现才能合并。
次大的值总要等到次大的与它方向相反的值出现才能合并。
以此类推。
那么我们只需要将lll,rrr数组排序,算∑max(ri,li)\sum max(r_i,l_i)∑max(ri,li)即可。
注意要开long long
时间复杂度:O(nlogn)O(nlogn)O(nlogn)
(好像讲的很不清楚,但我已经尽力了啊qwq…)
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
#define MAXN 100000
#define LL long long
int n;
int L[MAXN+5],R[MAXN+5];
LL ans;
bool cmp(int s1,int s2)
{
return s1>s2;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&L[i],&R[i]);
sort(L+1,L+n+1,cmp);
sort(R+1,R+n+1,cmp);
for(int i=1;i<=n;i++)
ans+=max(L[i],R[i]);
printf("%lld",ans+n);
}
E.Sergey and Subway
QwQ
体验感极差…
前面用了太长的时间,再次凉在E题…
[题解明天补]
注意要开long long