分手了不太开心QAQ,写篇博客吧。这题是区间dp的问题,题意就是给你无限个1145141919,有t次询问,询问的n小于等于5000,问是否存在这样的前缀使得你操作无限次加、乘和括号,没啥思路,看了大佬的代码,发现是有规律的?我这种菜鸡来打表都不会,那当且仅当前缀长度小于等于13,那就区间dp好了,dp[l][r][val] 代表l到r之间val这个值是不是合法,预处理的时候记得粘连在一起的部分也要算,例如“1145”,那么dp[1][4][1145]=true。
贴上代码OVO:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<vector>
#include<queue>
#include<stack>
#include<iostream>
#include<sstream>
#define x first
#define y second
#define lson u<<1
#define rson u<<1|1
#define pb push_back
#define pu pushup
#define mk make_pair
using namespace std;
#define ll long long
#define mod 1000000007
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
bool dp[20][20][5010];
int num[20]={
0,1,1,4,5,1,4,1,9,1,9,1,1,4,5,1};
int main()
{
int t;
cin>>t;
for(int i=1;i<=13;i++)
{
int temp=0;
for(int j=i;j<=13;j++)
{
temp=(temp*10+num[j]);
if(temp>=1 && temp<=5000)
dp[i][j][temp]=true;
}
}
for(int i=2;i<=13;i++)
for(int j=1;j+i-1<=13;j++)
{
int r=j+i-1;
for(int k=j;k<=r-1;k++)
{
for(int v1=1;v1<=5000;v1++)
{
if(!dp[j][k][v1]) continue;
for(int v2=1;v2<=5000;v2++)
{
if(!dp[k+1][r][v2]) continue;
if(v1+v2<=5000)
dp[j][r][v1+v2]|=dp[j][k][v1]&dp[k+1][r][v2];
if(v1*v2<=5000)
dp[j][r][v1*v2]|=dp[j][k][v1]&dp[k+1][r][v2];
}
}
}
}
for(int i=1;i<=5000;i++)
{
bool flag=false;
for(int j=1;j<=13;j++)
{
if(dp[1][j][i])
flag=true;
}
if(!flag) cout<<i<<endl;
}
while(t--)
{
int n;
cin>>n;
bool flag=false;
for(int i=1;i<=13;i++)
if(dp[1][i][n])
{
cout<<i<<endl;
flag=true;
break;
}
if(!flag)
puts("-1");
}
}