题目链接:https://ac.nowcoder.com/acm/contest/103957/E
题意:
给定一个数组,分别选出一些数使得其乘积之和是否等于x
思路:
将ai x bi 求和拆分成 ai之和 x bi之和
发现如果要让x等于这个两个数的乘积,那么这两个数分别是x的因子
将选取数看成01背包
记dp数组:dp[i,j]=1表示能到达这个状态,i表示行之和,j表示列之和
dp[i,j]=dp[i-a[k][j]
dp[i,j]=dp[i][j-a[k]]
如果dp[i,j]已经存在,那么就必须要continue
状态转移
对于单个方案的方法使用回溯,用分别记录pre分别记录走x还是走y
int arr[105];
int x,n;
int ok;void solve(){int m;cin>>n>>m;for(int i=1;i<=n;i++)cin>>arr[i];vector<vector<int>>dp(200,vector<int>(200,0));vector<vector<int>>pre(200,vector<int>(200,0));dp[0][0]=1;for(int i=1;i<=n;i++){for(int x=100;x>=0;x--){for(int y=100;y>=0;y--){if(dp[x][y])continue;if(x-arr[i]>=0&&dp[x-arr[i]][y]){dp[x][y]|=dp[x-arr[i]][y];pre[x][y]=arr[i];}else{if(y-arr[i]>=0&&dp[x][y-arr[i]]){dp[x][y]|=dp[x][y-arr[i]];pre[x][y]=-arr[i];}}}}}rep(i,1,m){cin>>x;int ok=0;for(int j=1;j*j<=x;j++){if(x%j==0){vector<int>res1,res2;int a=j,b=x/j;while((a!=0||b!=0)&&dp[a][b]){ok=1; if(pre[a][b]>0){res1.pb(pre[a][b]);a-=pre[a][b];}else{res2.pb(-pre[a][b]);b+=pre[a][b];}}if(ok){cout<<"Yes"<<endl;cout<<res1.size()<<' '<<res2.size()<<endl;for(int k=0;k<res1.size();k++){cout<<res1[k]<<' ';}cout<<endl;for(int k=0;k<res2.size();k++){cout<<res2[k]<<' ';}cout<<endl;break;}}}if(!ok)cout<<"No"<<endl;}}