【学习笔记】[AGC033E] Go around a Circle

32 篇文章 1 订阅
18 篇文章 0 订阅

不妨假设 S 0 = R S_0=R S0=R,做出如下观察:
1.1 1.1 1.1 不存在 B B B的连续段
1.2 1.2 1.2 不存在长度为偶数的 R R R的连续段
1.3 1.3 1.3 对于 S i = L S_i=L Si=L的情况,事实上这个棋子的移动方向是确定的,取决于上一段 R R R的奇偶性
1.4 1.4 1.4 S S S中连续的 R R R最短为 Y Y Y,如果圆上任意圆弧的长度 ≤ Y \le Y Y,那么可以从圆弧一端走到另一端,因此一定合法。能否证明这是充要的呢?取最长一段圆弧和最短一段 R R R,从圆弧的两端出发逆序操作就能找到出发点。因为圆弧两端奇偶性不同,因此必然存在一个点跨过了整段圆弧,证毕。 注意,我们只考虑长度为奇数的连续的 R R R
1.5 1.5 1.5对于 S S S中长度为偶数的连续的 R R R,发现可以缩掉,这样会出现连续的 B B B,那么只要不是出现在开头,这些 B B B都没有影响,因此如果开头的 R R R是奇数,那么不用考虑,如果是偶数,设长度为 Z Z Z,那么圆弧长度不能超过 Z + 1 Z+1 Z+1,据此对 Y Y Y修正即可。

大力 d p dp dp即可。复杂度 O ( n ) O(n) O(n)

似乎细节比较多

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int mod=1e9+7;
int n,m,a[200005],L(inf);
ll dp[200005][2],f[200005],res;
string s;
ll ask(int i,int j){
	return i<=0?0:dp[i][j];
}
signed main(){
	cin>>n>>m>>s;for(int i=0;i<m;i++)a[i+1]=(s[i]=='R');
	if(!a[1])for(int i=1;i<=m;i++)a[i]^=1;
	int j=1;
	for(int i=1;i<=m;i++){
		if(!a[i]){
			if((i-j)&1)L=min(L,i-j);
			else if(j==1)L=min(L,i);
			j=i+1;
		}
	}if(L==inf){
		f[1]=1;res=n+1;
		for(int i=2;i<n;i++){
			ll x=f[i-2];
			f[i]=(f[i-1]+x)%mod;
			res=(res+(n-i+1)*x)%mod;
		}cout<<res<<"\n";
		return 0;
	}
	dp[1][1]=1;if(L>=n-1&&(n-1&1))res=n;
	for(int i=2;i<n;i++){
		ll x=ask(i-1,i&1)-ask(i-L-2,i&1);
		dp[i][i&1]=(dp[i-1][i&1]+x)%mod;
		dp[i][!(i&1)]=dp[i-1][!(i&1)];
		if(n-i<=L&&(n-i&1))res=(res+(n-i+1)*x)%mod;
	}
	cout<<(res+mod)%mod;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值