CF1452【EDU】
Educational Codeforces Round 98
这场真的是思维手速场,ABCD过了之后直接罚做。
赛后学长告诉我n^3暴力过了,虽然后来他被hack了
不过也说明这题比较《思维》
下面放上题解
A. Robot Program
题意
从(0,0)走到(x,y),有上下左右原地不动四种操作。要求不能同时往一个方向走两次及以上。问最少要几次能到达。
思路
显然,我们发现,如果abs(x-y)<=1 ans=x+y;
反之 ans=x+y+abs(x-y)-1;
B. Toy Blocks
emmmm这题是一道神奇的题目,原本CF是ABCD的递推式难度上升,但是这题emmm感觉比C难一点点(大概
题意
对于一个由n个元素组成的数列a,问最少加几个数字,且对于每个数字a[i],都可以分给其他n-1个数,且能满足其他数字相等(语言组织fw
思路
计算数组内元素的和sum,若sum<=(n-1)* a[n],则ans=(n-1)*a[n]-sum;若不满足且sum%(n-1)==0 显然定能满足,则输出0,反之输出(n-1)-sum%(n-1);
代码实现
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
inline ll read(){
ll f=0,num;
char ch;
while(ch=getchar(),!isdigit(ch))if(ch=='-')f=1;num=ch-'0';
while(ch=getchar(), isdigit(ch))num=num*10+ch-'0';
return f?-num:num;
}
const int maxn=1e6+5;
ll a[maxn];
int main()
{
ll T,n;
T=read();
while(T--)
{
n=read();
ll sum=0,ans=0;
for(int i=1;i<=n;i++)cin>>a[i],sum+=a[i];
sort(a+1,a+1+n);
if(sum<=(n-1)*a[n])
cout<<(n-1)*a[n]-sum<<endl;
else
{
if(sum%(n-1)==0)
cout<<0<<endl;
else
cout<<(n-1)-sum%(n-1)<<endl;
}
}
return 0;
}
C. Two Brackets
题意
经典的括号配对
以下为合法的序列
1、空
2、(RBS)
3、[RBS]
4、RBS+RBS
每次可以删掉一次合法匹配,问最多可以删掉多少个括号
思路
我是笨蛋!!!
一看到这题就想到经典的括号序列问题,stack,都打算开始写了,突然灵光一闪
后来发现,简单地统计以下就可以了。
代码
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
inline int read(){
int f=0,num;
char ch;
while(ch=getchar(),!isdigit(ch))if(ch=='-')f=1;num=ch-'0';
while(ch=getchar(), isdigit(ch))num=num*10+ch-'0';
return f?-num:num;
}
const int N=2e5;
int T;
char a[N];
int get(char a){
if(a=='(')return 1;
else if(a==')') return -1;
if(a=='[')return 2;
else if(a==']') return -2;
}
int main(){
T=read();
while(T--){
scanf("%s",&a);
int len=strlen(a);
int ta=0,tb=0;
int ans=0;
for(int i=0;i<len;i++){
if(a[i]=='(')
ta++;
else if(a[i]=='[')
tb++;
else if(ta>0 && a[i]==')')
ta--,ans++;
else if(tb>0 && a[i]==']')
tb--,ans++;
}
cout<<ans<<endl;
}
return 0;
}
D. Radio Towers
题意
n+2个塔,每个位置安放喇叭的概率独立都是1/2,喇叭自己有个音量,以自身位置为中心向两边等距离的影响。问一个随机的方案存在一种设置喇叭的音量且满足:0和n+1的位置不被喇叭影响到,每个位置只被一个喇叭影响的概率
思路
sum1=dp[1]+dp[3]+(奇数)sum2=dp[0]+dp[2]+dp[4]+.(偶数)方案数除2的n次写个逆元就是答案
代码实现
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
const int maxn=1e6+3;
const int mod=998244353;
inline ll read(){
ll f=0,num;
char ch;
while(ch=getchar(),!isdigit(ch))if(ch=='-')f=1;num=ch-'0';
while(ch=getchar(), isdigit(ch))num=num*10+ch-'0';
return f?-num:num;
}
ll dp[maxn];
ll ksm(ll a,ll b)
{
int ans=1;
for(;b;b>>=1){
if(b&1) ans=(ll)ans*a%mod;
a=a*a%mod;
}
return ans;
}
int main(){
ll n;
n=read();
dp[0]=dp[1]=dp[2]=1LL;
ll sum1=1LL,sum2=2LL;
for(int i=3;i<=n;i+=2)
{
dp[i]=sum2;
sum1=(sum1+dp[i])%mod;
dp[i+1]=sum1;
sum2=(sum2+dp[i+1])%mod;
}
ll temp=ksm(2,n);
printf("%lld\n",dp[n]*ksm(temp,mod-2)%mod);
return 0;
}
E. Two Editorials
赛场上没有做出来的题目orz
题意
给你m个位于[1,n]的区间p,现在有长度为K的区间b和c。设对于区间p[i],定义a[i]为p[i]分别与b,c相交长度的较大值,现在问区间b和c位于何处时,∑pi最大,输出这个最大值,n,m,K<=2000
思路
【n^3】暴力枚举b,c的位置,n是2k,可以过(hack警告
【n^2】枚举b的位置,统计所有p[i]与b相交的长度之和,如果p[i]与c相交比b大,我们就要考虑第二个窗口的额外贡献,额外贡献num=len(c,p[i])-len(b,p[i]);
考虑枚举第二个窗口的右端点从小到大,根据滑动窗口的思想,每次滑动一格位置都需要考虑一下新增加的贡献和要删除的贡献。不过这些贡献来自于(li,ri),故干脆(li,ri)考虑会对第二个窗口在哪些位置产生贡献即可,进行区间加减操作,不过区间加可以改成修改差分数组。
代码实现
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
inline int read(){
int f=0,num;
char ch;
while(ch=getchar(),!isdigit(ch))if(ch=='-')f=1;num=ch-'0';
while(ch=getchar(), isdigit(ch))num=num*10+ch-'0';
return f?-num:num;
}
const int N=2005;
int n,m,K;
int l[N],r[N],a[N];
int adds[N],addt[N],subs[N],subt[N];//addt +1位置 subs -1 start subt -1 end
ll sum1[N],sum2[N];
void clr()
{
memset(adds,0,sizeof(adds));
memset(addt,0,sizeof(addt));
memset(subs,0,sizeof(subs));
memset(subt,0,sizeof(subt));
memset(sum1,0,sizeof(sum1));
memset(sum2,0,sizeof(sum2));
}
int main()
{
scanf("%d%d%d",&n,&m,&K);
for(int i=1;i<=m;i++)
scanf("%d%d",&l[i],&r[i]);
ll ANS=0,ans=0;
for(int i=1;i+K-1<=n;i++)//滑动窗口思想 l~l+K-1
{
clr();
int L=i,R=i+K-1;
ans=0;
for(int j=1;j<=m;j++)
{
a[j]=max(0,min(r[j],i+K-1)-max(l[j],i)+1);
ans+=a[j];
}
for(int j=1;j<=m;j++)
{
adds[l[j]+a[j]]++;
addt[min(r[j]+1,min(l[j]+K,n+1))]++;
subs[max(min(l[j]+K,n+1),r[j]+1)]++;
subt[min(r[j]-a[j]+1+K,n+1)]++;
}
ll tmp=0;
for(int j=1;j<=n;j++)
sum1[j]+=sum1[j-1]+adds[j]-addt[j]-subs[j]+subt[j];
for(int j=1;j<=n;j++)
sum2[j]=sum2[j-1]+sum1[j], tmp=max(tmp,sum2[j]);
ANS=max(ANS,ans+tmp);
}
printf("%lld\n",ANS);
return 0;
}
总结
1、其实还是跟上一场有点像吧,思维题出题速度不够快(手速场
2、对于跟以前题目有点像的题,不要被先入为主的思维影响,还是要基于题目本身进行思考。
3、希望下场能够继续加油(过E