【XSY2698】挑选子序列(二分,DLX)

7 篇文章 0 订阅

题面

挑选子序列

题解

非常 NOI 的一道题(给出很多奇奇怪怪的定义)。

先二分答案为 m i d mid mid,那么我们只需判定:是否存在子序列 s e q seq seq 使得串 s 1 , s 2 s1,s2 s1,s2 t t t 的距离不超过 m i d mid mid,即串 s 1 , s 2 s1,s2 s1,s2 各位置与 t t t 的距离不超过 m i d mid mid,那么对于串 s 1 , s 2 s1,s2 s1,s2 的每个位置 i i i s e q seq seq 中都应该存在一个位置 j j j 使得 i , j i,j i,j 的距离小于等于 m i d mid mid

我们可以先预处理出 s 1 , s 2 s1,s2 s1,s2 的每个位置 i i i t t t 的哪些位置 j j j 匹配能使得 i , j i,j i,j 距离小于等于 m i d mid mid,再转化一下,变为 t t t 的每个位置 j j j 能与 s 1 , s 2 s1,s2 s1,s2 的哪些位置 i i i 匹配使得 i , j i,j i,j 距离小于等于 m i d mid mid。那么现在问题变为了:能否选出 t t t 的不超过 m m m 个的位置,使得 s 1 , s 2 s1,s2 s1,s2 的每个位置都有匹配。

于是这就变成了一个可重复覆盖问题,可以用类似 DLX 的方法解决,需要加大量剪枝优化。比如用状压代替链表加速 DLX 的过程,因为这是可重复覆盖问题,我们不需要维护行的双向链表。

#include<bits/stdc++.h>

#define N 45
#define ll __int128
#define INF 0x7fffffff

using namespace std;

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

int T,n,m,nn,val[N];
char s[2][N],t[N];
int dis[N][N<<1];
int tot1[N];
ll full,sta[N],ss[N<<1];

vector<int>pos[N<<1];

int now;

inline int get(ll x)
{
    int bit=0;
    while(x>1) x>>=1,bit++;
    return bit;
}

int getp(ll x)
{
	int ans=0;
	for(int i=1;i<=nn;i++,x>>=1)
		if((x&1)&&tot1[i]<tot1[ans]) ans=i;
	return ans;
}

int mindep(ll x)
{
	int ans=0;
	while(x)
	{
		int p=get(x&-x)+1;
		x&=full^ss[p];
		ans++;
	}
	return ans;
}

int aaa[N];

bool dfs(ll x)
{
	if(!x) return 1;
	if(now==m) return 0;
	if(now+mindep(x)>m) return 0;
	int p=getp(x);
	now++;
	for(auto r:pos[p])
		if(dfs(x&(full^sta[r]))) return 1;
	now--;
	return 0;
}

bool check(int mid)
{
	for(int i=1;i<=nn;i++) pos[i].clear();
	for(int i=1;i<=n;i++)
	{
		sta[i]=0;
		for(int j=1;j<=nn;j++)
		{
			if(dis[i][j]<=mid)
			{
				pos[j].push_back(i);
				sta[i]|=((ll)1<<(ll)(j-1));
			}
		}
	}
	for(int i=1;i<=nn;i++)
	{
		tot1[i]=pos[i].size();
		if(!tot1[i]) return 0;
		ss[i]=0;
		for(int r:pos[i]) ss[i]|=sta[r];
	}
	now=0;
	return dfs(full);
}

int main()
{
	tot1[0]=INF;
	T=read();
	for(int fuck=1;fuck<=T;fuck++)
	{
		n=read(),m=read();
		nn=n<<1;
		full=((ll)1<<(ll)nn)-1;
		for(int i=0;i<n;i++) val[i]=read();
		scanf("%s%s%s",s[0]+1,s[1]+1,t+1);
		int l=0,r=0,ans;
		for(int i=1;i<=n;i++)
		{
			for(int j=0;j<2;j++)
			{
				for(int k=1;k<=n;k++)
				{
					dis[i][j*n+k]=abs(t[i]-s[j][k])+val[abs(i-k)];
					r=max(r,dis[i][j*n+k]);
				}
			}
		}
		while(l<=r)
		{
			int mid=(l+r)>>1;
			if(check(mid)) ans=mid,r=mid-1;
			else l=mid+1;
		}
		printf("Case #%d: %d\n",fuck,ans);
	}
	return 0;
}
/*
114514
3 2
0 1 2
azz
zaa
zza
7 2
0 1 2 3 4 5 6
elelele
psypsyp
congroo
*/
/*
1
20 5
57 194 48 150 18 110 131 88 94 137 140 159 95 53 43 127 175 7 64 55 
lkgjznqsxonxlpbomhix
lcxhxvjckjptarbdgmqj
szkdzeifsuqzafaxpcgk
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,你遇到的问题是在发送HTTP POST请求时收到了403 Forbidden的错误。这个错误通常表示你没有权限访问所请求的资源。 要解决这个问题,你可以采取以下步骤: 1. 首先,确保你的请求URL正确,并且你有权限访问该URL。你可以尝试在浏览器直接访问该URL,看看是否能够成功访问。 2. 如果你确定URL是正确的,并且你有权限访问,那么可能是你的请求缺少了必要的身份验证信息。你可以检查你的请求头是否包含了正确的身份验证信息,比如Token或用户名密码。 3. 另外,你还可以检查服务器端的配置,确保你的请求被正确地处理和授权。你可以查看服务器的日志,以了解更多关于403错误的详细信息。 综上所述,当你收到403 Forbidden错误时,你应该首先检查URL和权限,然后确保请求包含了正确的身份验证信息。如果问题仍然存在,你可以进一步检查服务器端的配置和日志,以找出问题的根本原因。 #### 引用[.reference_title] - *1* [kubeadm init报错10248...(The HTTP call equal to ‘curl -sSL http://localhost:10248/healthz‘ failed)](https://blog.csdn.net/weixin_45969972/article/details/123529966)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [c/c++使用libcurl库做http客户端及封装(HTTP_GET和HTTP_POST)](https://blog.csdn.net/xsy29000/article/details/103181267)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值