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| n−∣t∣ ,其中 ∣ t ∣ |t| ∣t∣ 是添加的子序列的长度(即价格等于删除的字符数)。您的任务是找出获得大小为 k k k 的集合 S S S 的最小可能总成本,或者报告不可能做到这一点。
1 ≤ n , k ≤ 100 1 \leq n,k \leq 100 1≤n,k≤100
思路
由于 k ≤ 100 k \leq 100 k≤100,且子序列长度越长约优,将原串加入队列,使用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} 1≤k≤1012
思路
- 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} dpi−1,j−1+dpi,j−1−dpi−1,lastc−1→dpi,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
- 选择最大数 m x mx mx时,满足选择两个数条件下选择出第二个数,再选择次大且不是选择的两个数的因数的数作为第三个数
- 不选择最大数
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;
}