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

posted @ 2020-11-21 20:26  Shayndel  阅读(77)  评论(0编辑  收藏  举报