0
点赞
收藏
分享

微信扫一扫

Educational Codeforces Round 93 (Rated for Div. 2)(A-D:三维DP)

瑾谋 2022-09-26 阅读 170

A:​​http://codeforces.com/contest/1398/problem/A​​

题意:

在非递减序列中找非法三角形

解析:

刚开始搞了个结构体排序,然后才发现给出的就是非递减。。。

看1,2,n,如果它三能组成三角形,一定不存在非法。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e4+20;
ll a[maxn];
struct node
{
int x;
int id;
}st[maxn];
bool cmp(node a,node b)
{
return a.x<b.x;
}
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int x1=a[1],x2=a[2],x3=a[n];
if((x1+x2)>x3&&(x3-x1)<x2&&(x3-x2)<x1&&(x2-x1)<x3)
cout<<"-1"<<endl;
else
cout<<"1 2 "<<n<<endl;
}
}

B:​​http://codeforces.com/contest/1398/problem/B​​

题意:

01字符串。

操作是每次删除一串连续1,得分为连续1的数目。两人依次操作,求先手的得分。

解析:

把所有连续1收集起来,排序,从大到小拿即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e4+20;
int a[maxn];
int b[maxn];
struct node
{
int x;
int id;
}st[maxn];
bool cmp(node a,node b)
{
return a.x<b.x;
}
int main()
{
int t;
cin>>t;
while(t--)
{
string s;
cin>>s;
int le=s.length();
int cnt=0,ok=0,tot=0;
for(int i=0;i<le;i++)
{
if(s[i]=='1')
{
int md=1,k;
int ok2=0;
if(i<le-1){
for(int j=i+1;j<le;j++)
{
if(s[j]=='1')
md++;
else
{
k=j;
ok2=1;
break;
}
}
}
if(!ok)
{
// cnt+=md;
ok=1;
}
else
ok=0;
b[tot++]=md;
if(!ok2)
{
break;
}
i=k-1;
}
}
ok=0;
cnt=0;
sort(b,b+tot);
for(int i=tot-1;i>=0;i--)
{
if(!ok)
{
cnt+=b[i];ok=1;
}
else
ok=0;
}
cout<<cnt<<endl;
}
}

C:​​http://codeforces.com/contest/1398/problem/C​​

题意:

求所有好序列的数目。

好序列:sum[j]-sum[i]==j-i+1

解析:

很明显,先把前缀和弄出来。

有:sumj-sum(i-1)==j-i+1

考虑把所有数字均-1,那么变成:sumj-sum(i-1)-(j-i+1)=0

那么就是求:所有区间和为0的区间数。

n*n很明显行不通。

Educational Codeforces Round 93 (Rated for Div. 2)(A-D:三维DP)_i++

如果某个sum出现多次,那么这一次与上一次的区间和就为0,与上上一次的区间和也为0,那么总的可构造的数目就是:cnt+=sum之前出现的数目

map记录次数,记得初始化mp[0]==0。

#include<bits/stdc++.h>
#include<map>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e5+20;
const ll inf=0x3f3f3f3f3f3f3f3f;
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
map<ll,int>m;
string s;
cin>>s;
m[0]++;
ll sum=0;
ll cnt=0;
for(int i=0;i<s.length();i++)
{
sum+=s[i]-'1';  //-1
cnt+=m[sum];
m[sum]++;
}
cout<<cnt<<endl;
}
}

D:​​http://codeforces.com/contest/1398/problem/D​​

题意:

给定若干个红色,绿色,蓝色的一对长度一样的棍子.问用这些棍子组成的颜色不同的矩形的面积的最大总和是多少.注意不能把两个相同颜色的一对棍子拆成两个分别去用.其次颜色不同指的是在两个集合里选的两对棍子.

解析:

考虑贪心,但是写着很麻烦。。

就看了题解,原来是个三维DP

定义dp[i][j][k],表示红色用了i个,绿色用了j个,蓝色用了k个的前提下,所获得的最大矩形面积和。

理解这个转移方程,还是之前的dp思路:选的大还是不选的大?

#include<bits/stdc++.h>
#include<map>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=2e2+20;
//const ll inf=0x3f3f3f3f3f3f3f3f;
int r[maxn],g[maxn],b[maxn];
ll dp[maxn][maxn][maxn];
int main()
{
int c1,c2,c3;
cin>>c1>>c2>>c3;
for(int i=1;i<=c1;i++) cin>>r[i];sort(r+1,r+1+c1);
for(int i=1;i<=c2;i++) cin>>g[i];sort(g+1,g+1+c2);
for(int i=1;i<=c3;i++) cin>>b[i];sort(b+1,b+1+c3);
ll maxx=0;
for(int i=0;i<=c1;i++)
{
for(int j=0;j<=c2;j++)
{
for(int k=0;k<=c3;k++)
{
if(i&&j) dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-1][k]+r[i]*g[j]);
if(i&&k) dp[i][j][k]=max(dp[i][j][k],dp[i-1][j][k-1]+r[i]*b[k]);
if(j&&k) dp[i][j][k]=max(dp[i][j][k],dp[i][j-1][k-1]+g[j]*b[k]);
maxx=max(maxx,dp[i][j][k]);
}
}
}
cout<<maxx<<endl;
}

 



举报

相关推荐

0 条评论