3.07训练赛

cf1183E

题意

简单版本和困难版本之间的唯一区别是约束。子序列是一种字符串,它可以通过删除一些符号或不删除符号而不改变剩余符号的顺序来从另一个字符串中导出。

.要删除的字符不需要连续,它们之间可以有任何间隔。例如,对于字符串“abaca”,以下字符串是子序列:“abaca”、“ABA”、“AAA”、“a”和“”(空字符串)。但以下字符串不是子序列:“aabaca”、“CB”和“BCAA”。您将得到一个由 n n n 个小写拉丁字母组成的字符串 s s s

在一步中,您可以取给定字符串的任何子序列 t t t ,并将其添加到集合 S S S 中。

集合 S S S 不能包含重复项。此移动花费 n − ∣ t ∣ n - |t| nt ,其中 ∣ t ∣ |t| t 是添加的子序列的长度(即价格等于删除的字符数)。您的任务是找出获得大小为 k k k 的集合 S S S 的最小可能总成本,或者报告不可能做到这一点。

1 ≤ n , k ≤ 100 1 \leq n,k \leq 100 1n,k100

思路

由于 k ≤ 100 k \leq 100 k100,且子序列长度越长约优,将原串加入队列,使用bfs跑出 k k k个子序列即可。

代码

#include<bits/stdc++.h>

#define ull unsigned long long 
#define ll long long
#define inf 0x3f3f3f3f
#define lc p<<1
#define rc p<<1|1
#define endl '\n'
#define all(a) a.begin()+1,a.end()
#define all0(a) a.begin(),a.end()
#define lowbit(a) (a&-a)
#define fi first
#define se second
#define pb push_back
#define yes cout<<"YES"<<endl
#define no cout<<"NO"<<endl

using namespace std;
const double eps=1e-6;
typedef pair<int,int>PII;
typedef array<int,3>PIII;
mt19937_64 rnd(time(0));  

void solve()
{
	int n,k;
	cin>>n>>k;
	string s;cin>>s;
	map<string,int>mp;
	ll ans=0;
	
	auto bfs=[&]()
	{
		queue<string>q;
		q.push(s);
		mp[s]=1;
		while(!q.empty() && k)
		{
			auto t=q.front();
			q.pop();
			k--;
			int len=t.size();
			ans+=n-len;
			for(int i=0;i<len;i++)
			{
				string res=t.substr(0,i)+t.substr(i+1,len-i);
				if(!mp[res])
				{
					mp[res]=1;
					q.push(res);
				}
			}
		}
	};
	
	bfs();
	if(k) cout<<-1<<endl;
	else cout<<ans<<endl;
}
	
	
int main()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	
	solve();
	
	return 0;
}

cf1183H

题意

1183E的hard版本,区别是 1 ≤ k ≤ 1 0 12 1 \leq k \leq 10^{12} 1k1012

思路

  • d p i , j dp_{i,j} dpi,j表示前 j j j个字符选 i i i个的不同子序列数量
  • 边界条件: d p 0 , i = 1 dp_{0,i}=1 dp0,i=1
  • 转移方程: d p i − 1 , j − 1 + d p i , j − 1 − d p i − 1 , l a s t c − 1 → d p i , j dp_{i-1,j-1}+dp_{i,j-1}-dp_{i-1,last_c-1} \rightarrow dp_{i,j} dpi1,j1+dpi,j1dpi1,lastc1dpi,j
  • l a s t c last_c lastc为字符上次出现位置

代码

#include<bits/stdc++.h>

#define ull unsigned long long 
#define ll long long
#define inf 0x3f3f3f3f
#define lc p<<1
#define rc p<<1|1
#define endl '\n'
#define all(a) a.begin()+1,a.end()
#define all0(a) a.begin(),a.end()
#define lowbit(a) (a&-a)
#define fi first
#define se second
#define pb push_back
#define yes cout<<"YES"<<endl
#define no cout<<"NO"<<endl

using namespace std;
const double eps=1e-6;
typedef pair<int,int>PII;
typedef array<int,3>PIII;
mt19937_64 rnd(time(0));  



void solve()
{
	ll n,k;
	cin>>n>>k;
	
	string s;cin>>s;
	s=" "+s;
	vector<vector<ll>>dp(n+1,vector<ll>(n+1));//前j个长度为i的不同子序列
	map<char,int>last;
	
	for(int i=0;i<=n;i++) dp[0][i]=1;
	
	for(int i=1;i<=n;i++)
	{
		for(auto c='a';c<='z';c++) last[c]=0;
		for(int j=i;j<=n;j++)
		{
			dp[i][j]=dp[i-1][j-1]+dp[i][j-1];
			if(last[s[j]]) dp[i][j]-=dp[i-1][last[s[j]]-1];
			last[s[j]]=j;
		}
	}
	
	
	ll sum=0;
	ll ans=0;
	
	for(int i=n;i>=0;i--)
	{
		if(sum+dp[i][n]>k)
		{
			ans+=(k-sum)*(n-i);
			sum=k;
			break;
		}
		sum+=dp[i][n];
		ans+=dp[i][n]*(n-i);
	}
	//cout<<sum<<endl;
	if(sum<k) cout<<-1<<endl;
	else cout<<ans<<endl;
	
}
	
	
int main()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	
	solve();
	
	return 0;
}

cf1183F

题意

给定 n n n个数,至多选择三个,且选择的数之间不存在倍数关系,求可以选择的最大和

思路

  • 选择1个数时,无疑选择最大数
  • 选择2个数时,选择最大数和次大且不是最大数因数的数,可以证明最优
  • 选择3个数时,考虑是否选择最大数 m x mx mx
    1. 选择最大数 m x mx mx时,满足选择两个数条件下选择出第二个数,再选择次大且不是选择的两个数的因数的数作为第三个数
    2. 不选择最大数 m x mx mx时,存在一种情况更优: m x 2 + m x 3 + m x 5 > m x \frac{mx}{2}+\frac{mx}{3}+\frac{mx}{5} > mx 2mx+3mx+5mx>mx
      三种情况分类讨论即可

代码

#include<bits/stdc++.h>

#define ull unsigned long long 
#define ll long long
#define inf 0x3f3f3f3f
#define lc p<<1
#define rc p<<1|1
#define endl '\n'
#define all(a) a.begin()+1,a.end()
#define all0(a) a.begin(),a.end()
#define lowbit(a) (a&-a)
#define fi first
#define se second
#define pb push_back
#define yes cout<<"YES"<<endl
#define no cout<<"NO"<<endl

using namespace std;
const double eps=1e-6;
typedef pair<int,int>PII;
typedef array<int,3>PIII;
mt19937_64 rnd(time(0));  



void solve()
{
	int n;cin>>n;
	vector<int>a(n+1);
	for(int i=1;i<=n;i++) cin>>a[i];
	sort(all(a),greater<int>());
	
	int res1=a[1];
	int ans=res1;
	int ok2,ok3,ok5;
	ok2=ok3=ok5=0;
	
	for(int i=2;i<=n;i++)
	{
		if(a[i]*2==res1) ok2=1;
		if(a[i]*3==res1) ok3=1;
		if(a[i]*5==res1) ok5=1;
	}
	if(ok2 && ok3 && ok5) ans=max(ans,res1/2+res1/3+res1/5);
	
	int res2=0;
	for(int i=2;i<=n;i++) if(res1%a[i]) {res2=a[i];break;}
	ans=max(ans,res1+res2);
	
	
	for(int i=2;i<=n;i++)
	{
		if((res1%a[i]) && (res2%a[i]))
		{
			ans=max(ans,res1+res2+a[i]);
			break;
		}
	}
	cout<<ans<<endl;
}
	
	
int main()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t;cin>>t;
	while(t--)
	solve();
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值