【C++动态规划】B3734 [信息与未来 2017] 加强版密码锁|普及+

本文涉及知识点

C++动态规划

B3734 [信息与未来 2017] 加强版密码锁

题目描述

乌龟偶然获得了一个宝箱,宝箱上又有一把密码锁。密码锁由 n n n 个拨盘组成,每个拨盘初始时有一个 0 0 0 到
99 99 99 之间的整数。向上拨使数字 x x x 变为 ( x + 1 )   m o d   100 (x+1) \bmod 100 (x+1)mod100,

向下拨使数字 x x x 变为 ( x + 99 )   m o d   100 (x+99) \bmod 100 (x+99)mod100。

因为密码锁年久失修,拨盘拨动的次数越多越费力。

如果一个拨盘被拨动 k k k 次,需要花费 k 2 k^2 k2 单位时间。

密码锁只有在所有的拨盘上的数字形成一个从左到

右严格递增的数列时才会解开。乌龟再次请你帮忙,求

解解开密码锁的最少时间。


试题中使用的生成数列 R R R 定义如下:整数 0 ≤ R 1 < 201701 0\leq R_1\lt 201701 0≤R1<201701 在输入中给出。

对于 i > 1 , R i = ( R i − 1 × 6807 + 2831 )   m o d   201701 i\gt 1,R_i=(R_{i−1}\times 6807+2831)\bmod 201701 i>1,Ri=(Ri−1×6807+2831)mod201701。

输入格式

两个整数 n , R 1 n,R_1 n,R1,表示拨盘的数量和数列生成的首项。从左向右数第 i ( 1 ≤ i ≤ n ) i(1\leq i\leq n) i(1≤i≤n) 个拨盘的初始数字为 R i   m o d   100 R_i \bmod 100 Rimod100。

输出格式

一个整数,表示解开密码锁的最少时间。

输入输出样例 #1

输入 #1

复制代码
10 4

输出 #1

复制代码
3338

说明/提示

30 % 30\% 30% 的数据满足 n ≤ 3 n\leq3 n≤3,所有数据满足 1 ≤ n ≤ 100 1\leq n\leq 100 1≤n≤100。

本题原始满分为 20 pts 20\text{pts} 20pts。

B3734 动态规划

动态规划的状态表示

dp[i][j]表示前i+1个锁盘严格升序,第i个(下标从0开始)锁盘j的最小成本数。 空间复杂度:O( ∑ \sum ∑N), ∑ \sum ∑是锁盘的可选值,本题是100。可以用滚动向量优化空间复杂度。

动态规划的填表顺序

枚举前置状态, i =1 to N-1 j = 0 to 99 j2= j+1 to 99

动态规划的转移方程

如果j2=j,增加的成本是0。

如果j2 > j,顺时针旋转 j2-j,逆时针旋转100-(j2-j)。

如果j2 < j,j2和j互换后,和j2>j同。

总结:k = min(abs(j2-j),100-abs(j2-j)),增加的成本是kk。

单个状态时间复杂度:O( ∑ \sum ∑),总时间复杂度:O(n ∑ ∑ \sum\sum ∑∑)

动态规划的初始值

dp[0]要单独计算。

动态规划的返回值

min(pre)

可以利用前缀和优化

枚举后置状态,dp[j2] = min(pre[0...j2-1])+本次的成本。时间复杂度 :O(n ∑ \sum ∑)

代码

核心代码

cpp 复制代码
#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>
#include<list>

#include <bitset>
using namespace std;

template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {
	in >> pr.first >> pr.second;
	return in;
}

template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {
	in >> get<0>(t) >> get<1>(t) >> get<2>(t);
	return in;
}

template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {
	in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);
	return in;
}

template<class T = int>
vector<T> Read() {
	int n;
	scanf("%d", &n);
	vector<T> ret(n);
	for (int i = 0; i < n; i++) {
		cin >> ret[i];
	}
	return ret;
}

template<class T = int>
vector<T> Read(int n) {
	vector<T> ret(n);
	for (int i = 0; i < n; i++) {
		cin >> ret[i];
	}
	return ret;
}

template<int N = 1'000'000>
class COutBuff
{
public:
	COutBuff() {
		m_p = puffer;
	}
	template<class T>
	void write(T x) {
		int num[28], sp = 0;
		if (x < 0)
			*m_p++ = '-', x = -x;

		if (!x)
			*m_p++ = 48;

		while (x)
			num[++sp] = x % 10, x /= 10;

		while (sp)
			*m_p++ = num[sp--] + 48;
		AuotToFile();
	}
	void writestr(const char* sz) {
		strcpy(m_p, sz);
		m_p += strlen(sz);
		AuotToFile();
	}
	inline void write(char ch)
	{
		*m_p++ = ch;
		AuotToFile();
	}
	inline void ToFile() {
		fwrite(puffer, 1, m_p - puffer, stdout);
		m_p = puffer;
	}
	~COutBuff() {
		ToFile();
	}
private:
	inline void AuotToFile() {
		if (m_p - puffer > N - 100) {
			ToFile();
		}
	}
	char  puffer[N], * m_p;
};

template<int N = 1'000'000>
class CInBuff
{
public:
	inline CInBuff() {}
	inline CInBuff<N>& operator>>(char& ch) {
		FileToBuf();
		ch = *S++;
		return *this;
	}
	inline CInBuff<N>& operator>>(int& val) {
		FileToBuf();
		int x(0), f(0);
		while (!isdigit(*S))
			f |= (*S++ == '-');
		while (isdigit(*S))
			x = (x << 1) + (x << 3) + (*S++ ^ 48);
		val = f ? -x : x; S++;//忽略空格换行		
		return *this;
	}
	inline CInBuff& operator>>(long long& val) {
		FileToBuf();
		long long x(0); int f(0);
		while (!isdigit(*S))
			f |= (*S++ == '-');
		while (isdigit(*S))
			x = (x << 1) + (x << 3) + (*S++ ^ 48);
		val = f ? -x : x; S++;//忽略空格换行
		return *this;
	}
	template<class T1,class T2>
	inline CInBuff& operator>>(pair<T1,T2>& val) {
		*this >> val.first >> val.second;
		return *this;
	}
	template<class T1, class T2,class T3>
	inline CInBuff& operator>>(tuple<T1, T2,T3>& val) {
		*this >> get<0>(val) >> get<1>(val) >> get<2>(val);
		return *this;
	}
	template<class T1, class T2, class T3,class T4>
	inline CInBuff& operator>>(tuple<T1, T2, T3,T4>& val) {
		*this >> get<0>(val) >> get<1>(val) >> get<2>(val) >> get<3>(val);
		return *this;
	}
	template<class T = int>
	inline CInBuff& operator>>(vector<T>& val) {
		int n;
		*this >> n;
		val.resize(n);
		for (int i = 0; i < n; i++) {
			*this >> val[i];
		}
		return *this;
	}
	template<class T = int>
	vector<T> Read(int n) {
		vector<T> ret(n);
		for (int i = 0; i < n; i++) {
			*this >> ret[i];
		}
		return ret;
	}
private:
	inline void FileToBuf() {
		const int canRead = m_iWritePos - (S - buffer);
		if (canRead >= 100) { return; }
		if (m_bFinish) { return; }
		for(int i = 0 ;i < canRead;i++)
		{
			buffer[i] = S[i];//memcpy出错			
		}
		m_iWritePos = canRead;
		buffer[m_iWritePos] = 0;
		S = buffer;
		int readCnt = fread(buffer + m_iWritePos, 1, N - m_iWritePos, stdin);
		if (readCnt <= 0) { m_bFinish = true; return; }
		m_iWritePos += readCnt;
		buffer[m_iWritePos] = 0;
		S = buffer;
	}
	int m_iWritePos = 0; bool m_bFinish = false;
	char buffer[N + 10], * S = buffer;
};

class Solution {
public:
	int Ans(const int N, int r1) {
		vector<int> rs = { r1 };
		for (int i = 1; i < N; i++) {
			rs.emplace_back((rs.back() * 6807LL + 2831) % 201701);
		}
		for (auto& i : rs) {
			i = i % 100;
		}
		vector<int> pre(100, 1e8);
		for (int j2 = 0; j2 < 100; j2++) {
			const int t = abs(j2 - rs[0]);
			const int k = min(t, 100 - t);
			pre[j2] = k * k;
		}
		for (int i = 1; i < N; i++) {
			vector<int> cur(100, 1e8);
			for (int j = 0; j < 100; j++) {
				for (int j2 = j + 1; j2 < 100; j2++) {
					const int t = abs(j2 - rs[i]);
					const int k = min(t, 100 - t);
					cur[j2] = min(cur[j2], pre[j] + k * k);
				}
			}
			pre.swap(cur);
		}
		return *min_element(pre.begin(), pre.end());
	}
};

int main() {	
#ifdef _DEBUG
	freopen("a.in", "r", stdin);
#endif // DEBUG	
	int n, r1;
	cin >> n >> r1;
#ifdef _DEBUG		
	//printf("N=%d,", N);
	//Out(mat, ",mat=");
	//Out(pos, ",pos=");
	/*Out(edge, "edge=");
	Out(que, "que=");*/
#endif // DEBUG	
	auto res = Solution().Ans(n, r1);
	cout << res;
	return 0;
}
相关推荐
是娇娇公主~3 小时前
力扣——105. 从前序与中序遍历序列构造二叉树详解
算法·leetcode·哈希算法
承渊政道3 小时前
【贪心算法】(经典实战应用解析(三):K次取反后最⼤化的数组和、按⾝⾼排序、优势洗牌、最⻓回⽂串、增减字符串匹配)
数据结构·c++·学习·算法·贪心算法·线性回归·哈希算法
凌波粒3 小时前
LeetCode--100.相同的树(二叉树)
算法·leetcode·职场和发展
alexwang2113 小时前
P16473 [GKS 2013 #B] Sudoku Checker题解
c++·算法·题解·洛谷
一条鱼头3 小时前
c++11语法点
开发语言·c++
Peter·Pan爱编程3 小时前
C++中的 const 与 volatile:比C强大十倍
c++·const·volatile·c++基础
lihao lihao3 小时前
MFC知识点
c++·mfc
Shadow(⊙o⊙)3 小时前
进程分析2.0——进程退出、进程等待-Linux重要经典模块
linux·运维·服务器·开发语言·c++·学习
无敌昊哥战神3 小时前
【机器学习扫盲】从预测 Score 到ACC、 Precision、Recall、ROC 曲线的白话全解
python·深度学习·算法·机器学习