题解:CF2028F Alice's Adventures in Addition
lcliruiyan · · 题解
题目传送门
题目思路
根据题意,表达式要按照正常的顺序进行计算,即先乘后加。因此,表达式可以看成若干项乘积进行求和。所以,我们从左往右处理数字时,要同时维护两个值:
- 当前段的乘积,记为
c 。 - 当前位置不包括该项已经确定的总和,记为
s 。
那么我们可以定义
由于
接下来考虑如何进行状态转移。假设当前已经处理完前
如果我们选择乘法,那么就将当前该项的乘积乘上
如果我们选择加法,结算当前的乘积
初始化将第一个数
而最后的答案可以这样计算:遍历所有状态,如果一个状态中 Yes。
如果遍历完所有状态仍然没有合法方案,输出 No。
code
#include<bits/stdc++.h>
using namespace std;
int t,n,m,a[200005];
bitset<10005>msk,st;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>t;
while(t--)
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
if(n==1)
{
if(a[1]==m)cout<<"YES\n";
else cout<<"NO\n";
continue;
}
msk.reset();
for(int i=0;i<=m;i++)
msk.set(i);
map<int,bitset<10005>>dp;
int sc=a[1];
st.reset();
st.set(0);
dp[sc]=st;
for(int i=2;i<=n;i++)
{
int x=a[i];
map<int,bitset<10005>>cur;
for(auto p:dp)
{
int c=p.first;
bitset<10005>bs=p.second;
int curm=0;
if(x!=0)
{
long long v=1ll*c*x;
if(v>m)curm=10005;
else curm=v;
}
cur[curm]|=bs;
int mul=x;
cur[mul]|=(bs<<c)&msk;
}
dp=move(cur);
}
bool flag=false;
for(auto p:dp)
{
int c=p.first;
bitset<10005>bs=p.second;
if(m>=c&&bs[m-c])
{
flag=true;
break;
}
}
if(flag)cout<<"YES\n";
else cout<<"NO\n";
}
return 0;
}