洛谷p1773 dp

其实, 这个dp还是蛮简单的,dp做多了后就会觉得方程不难出了,其实我的思路和大家都差不多,但是大部分都用了O(N^2)去预处理出这个区间内的值取模后是多少,其实这是完全没有必要的。听我来给你吹

f[i][j] = v:前i个字符各种操作后的数字为j,使用的最少的乘法个数为v,最后一个字符必须要落在i后面!!!!
为什么我们要强行让他最后一个乘法字符在i后面,因为如果不这么做,我们就无法知道他最后一个乘法字符在哪里,你就算不出一个值与前面的值相乘。
接下来考虑怎么转移
f[i][j] = min(f[k][z] + 1),
其中k<i,然后(z * [k+1,i])%mod ==j
放一个乘法字符在i后面,然后枚举前面的位置哪些可以算到最后的答案是j
很显然你只需要枚举一次前面所有的状态就可以得到i可以满足的每一个j,**不需要对于每一个j就去枚举一次所有状态!!!!**下一步,怎么得到某些区间的数字取mod后的结果是多少。
其实仔细观察可以知道,我们i是从1到len开始枚举的,然后对于每一个f[i][j], 后面需要利用到f[i][j]都是从i后面的数字到当前位置的数字,那么就是我们可以有一个num数组,这个数组存的内容就是
num[z] = v, 从z+1到当前位置的字符串取模后的值
当前的位置为i,那么在前面所有位置的num[z],都只需要*10+当前的字符,再去取模,那么就是当前需要的那个数字答案啦!

int v = (num[j] * 10 + (node[i] - '0')) % m;
			num[j] = v;

上面代码的i就是当前位置,j就是枚举前面所有的位置。
这样子去转移就是纯的O(N^2M),不需要额外加上
n^2的预处理!
小提醒,他是对m取模!!!我当初用之前设置的mod取模wa了好多次完全不知道哪错了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<time.h>
#include<string>
#include<stack>
#include<cmath>
#include<map>
#include<set>
#define int long long
//#define double long double
using namespace std;
#define PI 3.1415926535898 
#define eqs 1e-6
const long long max_ = 1000 + 7;
const int mod = 998244353;
const int inf = 1e9;
const long long INF = 1e18;
int read() {
	int s = 0, f = 1;
	char ch = getchar();
	while (ch<'0' || ch>'9') {
		if (ch == '-')
			f = -1;
		ch = getchar();
	}
	while (ch >= '0'&&ch <= '9') {
		s = s * 10 + ch - '0';
		ch = getchar();
	}
	return s * f;
}
int min(int a, int b) {
	return a < b ? a : b;
}
int max(int a, int b) {
	return a > b ? a : b;
}
char node[max_];
int num[max_],f[max_][60],m;
signed main() {
	std::ios::sync_with_stdio(false);
	cin >> node + 1;
	cin >> m;
	int len = strlen(node + 1);
	memset(f, 23, sizeof(f));
	//memset(num, 0, sizeof(num));
	f[0][1] = -1;
	for (int i = 1; i <= len; i++) {
		for (int j = 0; j < i; j++) {
			int v = (num[j] * 10 + (node[i] - '0')) % m;
			num[j] = v;
			for (int z = 0; z < m; z++) {
				if (f[j][z] > len) continue;
				int vv = ((z % m)*(v % m)) % m;
				f[i][vv] = min(f[i][vv], f[j][z] + 1);
			}
		}
	}
	for (int i = 0; i < m; i++) {
		if (f[len][i] < len) {
			cout << i << " " << f[len][i] << " "; break;
		}
	}
	for (int i =m - 1; i >= 0; i--) {
		if (f[len][i] < len) {
			cout << i << " " << f[len][i]; break;
		}
	}
	return 0;
}
全部评论

相关推荐

过往烟沉:我说什么来着,java就业面就是广!
点赞 评论 收藏
分享
有趣的牛油果开挂了:最近这个阶段收到些杂七杂八的短信是真的烦
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务