小白月赛51 补题 E G F

E题

经过思考后发现a只有递增的时候条件才会有用,所以我们创建数组时只需要把递增的a加进去就可以,然后思考一开始的n的取值有【n*b,(n+1)*b-1】这个区间内,然后我们就可以区间取交集,把这些符合n的区间加起来。

using Pll=pair<ll,ll>;
int x;
ll n;
vector<Pll> v;
ll a[MAXN];
ll b[MAXN];

ll query(ll l,ll r,ll x){
	ll tmp1=x*n,tmp2=(n+1)*x-1;
	l=max(l,tmp1);
	r=min(r,tmp2);
	return max(0ll,r-l+1);
}


void solve(){
	scanf("%d",&x);
	int mx=0;
	for(int i=1;i<=x;i++){
		scanf("%lld %lld",a+i,b+i);
		if(a[i]>mx){
			mx=a[i];
			v.push_back(Pll(a[i],b[i]));
		}
	}
	scanf("%lld",&n);
	if(n>=mx) return void(printf("1"));
	ll ans=0;
	for(int i=0;i<v.size();i++){
		if(i) ans+=query(v[i-1].first,v[i].first-1,v[i].second);
		else ans+=query(1,v[i].first-1,v[i].second);
	}
	printf("%lld",ans);
}

F题

要求所以子区间的平均数和,可以思考得出一个规律

 其他的情况同理,所以可以直接写代码了,注意要求个逆元就行

const int mod=1e9+7;
int n;
ll a[MAXN];
ll pre[MAXN];
ll sum[MAXN];

ll q_pow(ll a,ll b){
	ll rec=1;
	while(b){
		if(b&1){
			rec=rec*a%mod;
		}
		b>>=1;
		a=a*a%mod;
	}
	return rec;
}

void solve(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",a+i);
		pre[i]=(a[i]+pre[i-1])%mod;
	}
	for(int i=1;i<=n;i++){
		if(i<=n/2+n%2){
			sum[i]=(sum[i-1]+pre[n-i+1]-pre[i-1])%mod;
		}else{
			sum[i]=sum[n-i+1];
		}
	}
	ll ans=0;
	for(int i=1;i<=n;i++){
		ans+=sum[i]*q_pow(i,mod-2);
		ans%=mod;
	}
	printf("%lld\n",ans);
}

G题

刚好最近在学字符串哈希它就来了,直接正序倒序求哈希,然后开始枚举删除的后缀长度,前缀那一段就只有1,本来就是回文串2.差一个是回文串3.差很多个是 就这三种分别判断一下就行,其中还要区分奇偶串,特判一下就OK,判断是否为差一个为回文串可以利用二分求最大回文子串,然后到达那个不是的字符时再判断其剩下两边的串是否为回文即可说明他是否是差一个为回文串。

int n;
char s[MAXN];
ull h1[MAXN];
ull h2[MAXN];
ull g[MAXN];
const int p=131;
ull query1(int l,int r){
	return h1[r]-h1[l-1]*g[r-l+1];
}
ull query2(int l,int r){
	return h2[l]-h2[r+1]*g[r-l+1];
}

void solve(){
	scanf("%d",&n);
	scanf("%s",s+1);
	g[0]=1;
	for(int i=1;i<=n;i++){
		g[i]=g[i-1]*p;
		h1[i]=h1[i-1]*p+(ull)s[i];
	}
	int ans=0;
	for(int i=n;i>=1;i--) h2[i]=h2[i+1]*p+(ull)s[i];
	for(int i=0;i<n;i++){
		int tmp=(n-i)/2+(n-i)%2;
		if((n-i)%2){
			if(query1(1,n-i)==query2(1,n-i)) ans+=26;
			else{
				int l=0,r=tmp-1;
				while(l<=r){
					int mid=l+r>>1;
					if(query1(tmp-mid,tmp-1)==query2(tmp+1,tmp+mid)) l=mid+1;
					else r=mid-1;
				}
				if(query1(1,tmp-l-1)==query2(tmp+l+1,n-i)) ans+=2;
			}
		}else{
			if(query1(1,n-i)==query2(1,n-i)) ans+=1;
			else{
				int l=0,r=tmp;
				while(l<=r){
					int mid=l+r>>1;
					if(query1(tmp-mid+1,tmp)==query2(tmp+1,tmp+mid)) l=mid+1;
					else r=mid-1;
				}
				if(query1(1,tmp-l)==query2(tmp+l+1,n-i)) ans+=2;
			}
		}
	}
	printf("%d",ans);
}

个人认为这套题出的还是很好的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值