Educational Codeforces Round 93 (Rated for Div. 2)
A
题意:
给你一串递增数列,找出不能构成三角形的三个数,否则输出$-1$。
分析:
签到题,一开始没看到是递增的,还用$pair$排了个序(活该)。直接判断最小的两个和最大的关系,如果这个可以那么全部都可以。
1 #include<bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 const ll maxn=1e5+100;
5 const ll mod=1e9+7;
6 const ll inf=0x3f3f3f3f3f3f3f3f;
7 ll t,n;
8 ll a[maxn];
9 int main(){
10 //freopen("in.txt","r",stdin);
11 cin>>t;
12 while(t--){
13 cin>>n;
14 for(int i=0;i<n;i++)cin>>a[i];
15 if(a[0]+a[1]<=a[n-1]){
16 cout<<1<<' '<<2<<' '<<n<<endl;
17 }else{
18 cout<<-1<<endl;
19 }
20 }
21 return 0;
22 }
B
题意:
给你一串$01$列,每次可以拿走连续的数字,得到的分数就是拿走的$1$的个数。两个选手都最优选择,问先手能拿多少分。
分析:
把原来的字符串处理一下,连续的$1$都加起来,把$0$删掉,可以知道如果有连续的那必然先拿最长的,而且后手也是那当前最长的。所以给这些数字排序,反转,取偶数位即可。
1 #include<bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 const ll maxn=1e5+100;
5 const ll mod=1e9+7;
6 const ll inf=0x3f3f3f3f3f3f3f3f;
7 ll t,n,b[maxn];
8 string a;
9 int main(){
10 //freopen("in.txt","r",stdin);
11 cin>>t;
12 while(t--){
13 cin>>a;
14 ll cnt=0;
15 for(int i=0;i<a.size();){
16 if(a[i]=='0'){
17 while(a[i]=='0')i++;
18 }else{
19 ll cn=0;
20 while(a[i]=='1')cn++,i++;
21 b[cnt++]=cn;
22 }
23 }
24 sort(b,b+cnt);reverse(b,b+cnt);
25 ll al=0;
26 for(int i=0;i<cnt;i++){
27 if(i%2==0) al+=b[i];
28 }
29 cout<<al<<endl;
30 }
31 return 0;
32 }
C
题意:
给你一串数列$a_i$,问有多少个$i \le j$满足$\sum_{k=i}^j{a_k}=j-i+1$。
分析:
变形一下,得到$\sum_{k=i}^j{(a_k-1)}=0$。那就很显然了,前缀和,然后找到区间和为$0$的个数,那么这个$sum[i]$和$sum[j]$只能是相等或者本身为$0$。造一个新的数列,然后$map$记录元素出现次数,然后一加就行,$0$要额外加本身。
1 #include<bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 const ll maxn=1e5+100;
5 const ll mod=1e9+7;
6 const ll inf=0x3f3f3f3f3f3f3f3f;
7 ll t,n,a[maxn],sum[maxn];
8 string s;
9 map<ll,ll> mp;
10 int main(){
11 //freopen("in.txt","r",stdin);
12 cin>>t;
13 while(t--){
14 cin>>n>>s;
15 for(int i=0;i<n;i++)a[i]=s[i]-'0'-1;
16 sum[0]=a[0];//cout<<sum[0]<<' ';
17 for(int i=1;i<n;i++) sum[i]=sum[i-1]+a[i];//cout<<sum[i]<<' ';cout<<endl;
18 ll res=0,ze=0;
19 for(int i=0;i<n;i++){
20 mp[sum[i]]++;
21 }
22 for(auto i:mp){
23 ll te=i.second;
24 if(i.first==0){
25 res+=te+te*(te-1)/2;
26 }else{
27 if(te>1){
28 res+=te*(te-1)/2;
29 }
30 }
31 }cout<<res<<endl;
32 mp.clear();
33 }
34 return 0;
35 }
D
题意:
给你三种颜色的木棒,每次选择两个颜色不一样的变成矩形并获得面积,问最大获得多少面积。
分析:
没做出来,用堆或者,放在一个大数组里面都不行,明天看看题解吧。其实我一开始就知道是$dp$,奈何写不出来,看了眼别人的提交以后恍然大悟。
用一个三维的数组$dp[i][j][k]$,表示已经取了$r,g,b$三种木棒的前$i,j,k$大的木棒。那么状态转移方程就是:
$$
dp\left[ i \right] \left[ j \right] \left[ k \right] =\max \left( \begin{array}{c}
dp\left[ i-1 \right] \left[ j-1 \right] \left[ k \right] +r\left[ i \right] g\left[ j \right]\\
dp\left[ i \right] \left[ j-1 \right] \left[ k-1 \right] +g\left[ j \right] b\left[ k \right]\\
dp\left[ i-1 \right] \left[ j \right] \left[ k-1 \right] +r\left[ i \right] b\left[ k \right]\\
\end{array} \right)
$$
对于初始条件,$dp[0][0][0]=0$,其他的均赋值为$-1$,然后三重循环就可以了。
1 #include<bits/stdc++.h>
2 #define rep(i,a,b) for(ll i=(a);i<=(b);i++)
3 #define per(i,a,b) for(ll i=(a);i>=(b);i--)
4 using namespace std;
5 typedef long long ll;
6 const ll maxn=1e5+100;
7 const ll mod=1e9+7;
8 const ll inf=0x3f3f3f3f3f3f3f3f;
9 ll t,r[1000],g[1000],b[1000],num[5];
10 ll dp[205][205][205];
11 int main(){
12 //freopen("in.txt","r",stdin);
13 rep(i,1,3) cin>>num[i];
14 rep(i,1,num[1]) cin>>r[i];
15 rep(i,1,num[2]) cin>>g[i];
16 rep(i,1,num[3]) cin>>b[i];
17 sort(r+1,r+num[1]+1),reverse(r+1,r+num[1]+1);
18 sort(g+1,g+num[2]+1),reverse(g+1,g+num[2]+1);
19 sort(b+1,b+num[3]+1),reverse(b+1,b+num[3]+1);
20 memset(dp,-1,sizeof(dp));
21 dp[0][0][0]=0;
22 ll res=0;
23 rep(i,0,num[1]){
24 rep(j,0,num[2]){
25 rep(k,0,num[3]){
26 if(i>0&&j>0&&dp[i-1][j-1][k]>=0){
27 dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-1][k]+r[i]*g[j]);
28 }
29 if(k>0&&j>0&&dp[i][j-1][k-1]>=0){
30 dp[i][j][k]=max(dp[i][j][k],dp[i][j-1][k-1]+b[k]*g[j]);
31 }
32 if(i>0&&k>0&&dp[i-1][j][k-1]>=0){
33 dp[i][j][k]=max(dp[i][j][k],dp[i-1][j][k-1]+r[i]*b[k]);
34 }
35 res=max(res,dp[i][j][k]);
36 }
37 }
38 }
39 cout<<res<<endl;
40 return 0;
41 }