Codeforces 成长之路 #689 div2 题解
日期: 2020-12-12 分类: 跨站数据测试 474次阅读
Codeforces 成长之路 #689 div2 题解
比赛地址
https://codeforces.ml/contest/1461
A. String Generation
题目大意
输出一个只能由小写字母a、b、c组成的长度为n且最长子回文串长度不超过k的序列。
解题思路
直接按照abcabc轮流输出即可,这时候最长子回文串长度为1。
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve()
{
int n,k;cin>>n>>k;
for(int i=1;i<=n;i++)
if(i%3==0)
cout<<'a';
else if(i%3==1)
cout<<'b';
else if(i%3==2)
cout<<'c';
cout<<endl;
}
int main()
{
int T;cin>>T;
while(T--)
solve();
}
B. Find the Spruce
题目大意
给你一个n*m矩阵,由.和*组成,其中*为树的叶子。问矩阵种能组成树的最多数量是多少。树如图下所示,一个小黑块等于一个*。
解题思路
数据范围才500,可以用n^3的暴力解决。比赛时本人写了个动态规划,但是注意使用short和bool,不然会MLE。其中 dp[i][j] 代表矩阵中 (i,j) 向前有多少个连续的*,is[i][j][k] 代表 (i,j) 之前的k个元素是一棵树的底层。然后我们只要枚举最下面一层的大小,假设为k,则状态转移方程为
if(dp[i][j]>=k&&is[i-1][j-1][k-2])
ans++,is[i][j][k]=1;
含义是,(i,j) 向前有至少k个连续的*,而且上一层的 (i-1,j-1) 向前的k-2个元素是一棵树的最底层,那么第 (i,j) 向前的k个连续* 可以拼凑在上面一棵树之下作为新的底层形成一颗新的树。
AC代码
#include<bits/stdc++.h>
#define MAXN 505
using namespace std;
typedef long long ll;
short dp[MAXN][MAXN];
bool is[MAXN][MAXN][MAXN];
char mmap[MAXN][MAXN];
void clr(int n,int m)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
dp[i][j]=0;
for(int k=1;k<=m;k++)
is[i][j][k]=0;
}
}
void solve()
{
int n,m;cin>>n>>m;
ll ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>mmap[i][j];
if(mmap[i][j]=='*')
{
is[i][j][1]=dp[i][j]=1;
if(mmap[i][j-1]=='*')
dp[i][j]+=dp[i][j-1];
ans++;
}
}
for(int k=3;k<=m;k+=2)
for(int i=2;i<=n;i++)
for(int j=1;j<=m;j++)
if(dp[i][j]>=k&&is[i-1][j-1][k-2])
ans++,is[i][j][k]=1;
cout<<ans<<endl;
clr(n,m);
}
int main()
{
int T;cin>>T;
while(T--)
solve();
}
C. Random Events
题目大意
给你一个1~n的随机序列,再给你n次操作,每次操作有一定概率p触发,操作的方式是对0 ~ r 进行排序,问你整个序列最终变成有序的概率是多少。
解题思路
比较简单的数学题。假设从0~m是无序序列,m+1到n是有序序列,那我们需要知道至少有一次 r>=m 的操作的发生的概率就是我们要求的概率。如果序列本身就是有序的,则概率为1。
AC代码
#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;
typedef long long ll;
int a[MAXN];
int dp[MAXN];
void solve()
{
int n,m;cin>>n>>m;
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
cin>>a[i];
double np=1;
for(int i=n;i>=1&&a[i]==i;i--)
dp[i]=1;
dp[n+1]=1;
for(int i=1;i<=m;i++)
{
int aa;double b;
cin>>aa>>b;
if(dp[aa+1]) //说明这次操作的r>=m
np*=(1-b);
}
np=1-np;
if(dp[1])
np=1;
printf("%.8f\n",np);;
}
int main()
{
int T;cin>>T;
while(T--)
solve();
}
D. Divide and Summarize
题目大意
给你一个数组,设mid=(数组中最大元素+最小元素)/2,你可以把小于等于mid的数放在一堆,大于mid的数放在一堆形成两个新的数组。同样,新形成的两个数组也可以进行相同操作。给你一堆询问,每次询问给出一个数,问是否有通过这样方式构造的数组的元素和等于这个数。
解题思路
直接排序以后二分模拟他的操作,并且把所有可能的值存下来,计算数组和的时候可以用前缀和差分数组O(1)计算,最后对着记录下来的答案输出询问。听说unordered_map在比赛中有可能被hack,所以建议以后老老实实用logn的map。
AC代码
#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;
typedef long long ll;
unordered_map<ll,bool> um;
int a[MAXN];
ll premix[MAXN];
void func(int l,int r)
{
if(l>=r) return;
int mid=(a[l]+a[r])/2;
int pos=upper_bound(a+l,a+r+1,mid)-a;
if(pos==r+1)return;
um[premix[pos-1]-premix[l-1]]=1;
um[premix[r]-premix[pos-1]]=1;
func(l,pos-1);
func(pos,r);
}
void solve()
{
int n,m;cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
premix[i]=premix[i-1]+a[i];
um[premix[n]]=1;
func(1,n);
for(int i=1;i<=m;i++)
{
int t;cin>>t;
cout<<(um[t]?"YES":"NO")<<endl;
}
um.clear();
}
int main()
{
int T;cin>>T;
while(T--)
solve();
}
除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog
精华推荐