D. Doin' Time ——区间dp
题意:
给你长度为n的数列(n <= 300)每次可以选择一个数ax 与它后面的那个数ax+1合并成一个新的数ax*ax+1 然后得到(ax-ax+1)2 的分数 一共n-1次操作
求最多可以得到多少分数
思路:
区间dp
最后肯定是由两个数合并成一个数 就是要考虑 分成哪两段 才能使答案更优 而每一段又可以分成两段 只要找到每段最优的情况(即从小段的最优情况转移给大段) 然后输出整段最优解
预处理 利用前缀积 和 逆元 方便处理后续数据
#include<iostream> #include<algorithm> #include<string> #include<set> #include<map> #include<cstdio> #include<cmath> #include<cstring> #include<queue> #include<stack> #include<unordered_map> #include<iomanip> #define ll long long #define ull unsigned long long #define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr) #define m_p make_pair #define pi acos(-1) using namespace std; const int N = 2e5 + 5; const int M = 5e5 + 5; const double eps = 1e-4; const int inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3f; const ll mod = 1000003; ll n, m, k, a[310], pre[310], pre2[310], dp[310][310]; ll qsm(ll a, ll b){ int ans = 1; while(b){ if(b & 1) ans = ans * a % mod; a = a * a % mod; b >>= 1; } return ans; } void solve() { cin >> n; for(int i = 1; i <= n; i++){ cin >> a[i]; } pre[0] = pre2[0] = 1; for(int i = 1; i <= n; i++){ //前缀积 pre[i] = pre[i - 1] * a[i] % mod; //逆元 即 前缀积的倒数 pre2[i] = qsm(pre[i], mod - 2); } ll l, r; //i代表区间长度 从小到大枚举长度 然后进行状态转移 for(int i = 2; i <= n; i++){ //相同长度的不同段的最优情况 for(int j = 1; j + i - 1 <= n; j++){ //左右区间 有区间不能超界 l = j, r = i + j - 1; //枚举K 中间端点 即这个区间从哪两个更短的区间转移过来最优 for(int k = l; k <= r - 1; k++){ dp[l][r] = max(dp[l][r], dp[l][k] + dp[k + 1][r] + (pre[k] * pre2[l - 1] % mod - pre[r] * pre2[k] % mod) * (pre[k] * pre2[l - 1] % mod - pre[r] * pre2[k] % mod)); } } } cout << dp[1][n] << "\n"; } signed main() { IOS; ll t = 1; //cin >> t; while(t--) solve(); return 0; }
分类:
dp
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现