Educational Codeforces Round 111 (Rated for Div. 2) E - Stringforces

link

二分+状压dp 这个dp设计的太妙了
学到了 f[i][j] 处理完第i个字符 从第j个位置开始的 位置
dp[i] 处理完当前 i状态的字符的 需要的最远的位置 最后判断小于等于 n+1即可

#include <bits/stdc++.h>
using namespace  std;
#define  int long long
//typedef long long ll;
typedef pair<int,int> pii;
#define x first
#define y second
#define pb  push_back
#define inf 1e18
#define IOS   std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define  fer(i,a,b)  for(int i=a;i<=b;i++)
#define  der(i,a,b)  for(int i=a;i>=b;i--)
const int maxn=1e5+10;
const int mod=1e9+7;
int qmi(int a,int b) {
	int res=1;
	while(b) {
		if(b&1) res=res*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return res;
}
const int N=2e5+10;
int dr[4][2]= {{-1,0},{1,0},{0,-1},{0,1}};
int n,k;
string s;
int dp[1<<17];
int f[20][N];
bool check(int mid) {
	memset(dp,0x3f3f3f,sizeof(dp));
	memset(f,0x3f3f3f,sizeof(f));
	for(int i=0; i<k; i++) {
		int t=0;
		for(int j=n; j>=1; j--) {
			if(s[j]=='?'||s[j]==i+'a')t++;
			else t=0;
			if(t>=mid)f[i][j]=mid+j;
			else f[i][j]=f[i][j+1];
		}
	}
	dp[0]=1;
	for(int i=0; i<1<<k; i++) {
		for(int j=0; j<k; j++) {
			if(i>>j&1)continue;
			if(dp[i]<=n+1)dp[i|(1<<j)]=min(dp[i|(1<<j)],f[j][dp[i]]);
		}
	}
	if(dp[(1<<k)-1]>n+1)return false;
	return true;
}


void solve() {
	cin>>n>>k;
	cin>>s;
	s=" "+s;
	int l=0,r=n;
	while(l<=r) {
		int mid=(l+r)>>1;
		if(check(mid))l=mid+1;
		else r=mid-1;
	}
	cout<<r<<endl;
}

signed main() {
	IOS;
	int _=1;
	//cin>>_;
	while(_--) solve();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值