D - Prince and Princess

本文介绍了一种解决最长公共子串问题的高效算法。通过将问题转化为寻找最长递增子序列,结合二分查找技巧,成功将时间复杂度从O(N^2)降低到O(N log N),并附带实现代码。

https://vjudge.net/contest/221630#problem/D
这个题目是公主和王子都从(0,0)走到(n,n),只不过路径不完全相同,让你找出两人的最大可以共同走过的地方。

Sample Input

1
3 6 7
1 7 5 4 8 3 9
1 4 3 5 6 2 8 9

Sample Output

Case 1: 4

解题思路:
这个题其实是其最长公共子串问题,但是因为题目是255*255的,如果按照LCS算法进行得话,时间复杂度为(255*255)^2,会超时,所以改成求最大上升子序列。
数列a和数列b
将数列b中的数按其在数列a中出现的顺序重新编号,a中没有的则不记录
如a: 1 7 5 4 8 3 9
b: 1 4 3 5 6 2 8 9 重新编号后: 0 3 6 2 4 6
然后求b的最长上升子序列。因为求最长上升子序列的时间复杂度依然为n^2,但是可以改进,使用二分法来求第一个大于num的下标,故可以将时间复杂度减小为(nlogn)。
dp[n]始终保持上升子列长度为n的最后一位数(越小越好)保持最小值。

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

int num[255*255],bnum[255*255],dp[255*255];
int n,p,q;

int find(int i,int j,int num){//二分法找到dp[]中第一个大于num的那个数的下标 
    while(i<j){
        int mid=(i+j)/2;
        if(dp[mid]>num) j=mid;
        else i=mid+1;
    }
    return j;
}
int main(){
    int t;
    cin>>t;
    int tt=0;
    while(t--){
        tt++;
        cin>>n>>p>>q;
        int sa,sb;
        memset(num,-1,sizeof(num));
        memset(bnum,0,sizeof(bnum));
        memset(dp,0,sizeof(dp));
        for(int i=0;i<=p;i++){
            cin>>sa;
            num[sa]=i;
        }
        int m=0;
        for(int i=0;i<=q;i++){
            cin>>sb;
            if(num[sb]!=-1)
                bnum[m++]=num[sb];
        }
        dp[1]=bnum[0];
        int k=1,mid;
        for(int i=1;i<m;i++){
            if(bnum[i]>dp[k]) dp[++k]=bnum[i];
            else{
                mid=find(0,k,bnum[i]);
                dp[mid]=bnum[i];
            } 
        }
        printf("Case %d: %d\n",tt,k);
    }
    return 0;
}
Dormand-Prince 方法是一种常用的数值积分技术,专门用于求解常微分方程(ODEs)的初值问题。该方法属于显式龙格-库塔(Runge-Kutta)家族,具体来说是一种 (4,5) 阶的嵌套龙格-库塔方法,通常被称为 Dormand-Prince 对(Dormand-Prince pair)。它通过同时提供四阶和五阶精度的解来估计局部截断误差,并据此自适应地调整步长,从而在保证精度的同时提高计算效率。 这种方法的核心思想是基于一系列中间斜率的加权平均来逼近下一时刻的状态值。Dormand-Prince 方法的 Butcher 表如下所示: ``` 0 | 1/5 | 1/5 3/10 | 3/40 9/40 4/5 | 44/45 -56/15 32/9 8/9 | 19372/6561 -25360/2187 64448/6561 -212/729 1 | 9017/3168 -355/33 46732/5247 49/176 -5103/18656 1 | 35/384 0 500/1113 125/192 -2187/6784 11/84 |--------------------------------------------------------- | 35/384 0 500/1113 125/192 -2187/6784 11/84 0 | 5179/57600 0 7571/16695 393/640 -92097/339200 187/2100 1/40 ``` 其中最后一行分别是五阶和四阶解的权重系数。通过比较这两个解之间的差异,可以估计误差并据此调整步长。 在实际应用中,Dormand-Prince 方法广泛用于各种科学计算软件包中,例如 MATLAB 的 `ode45` 函数就是基于此方法实现的一阶 ODE 求解器。`ode45` 是一种自适应步长控制的求解器,适用于大多数非刚性问题[^2]。 ### 实现示例 以下是一个使用 Python 编写的简单 Dormand-Prince 方法实现,用于求解一个简单的 ODE: ```python import numpy as np def dormand_prince(f, t_span, y0, h): """ Dormand-Prince 方法求解 ODE 参数: f - 右手边函数 f(t, y) t_span - 时间区间 [t_start, t_end] y0 - 初始条件 h - 初始步长 返回: t_values - 时间点列表 y_values - 解列表 """ t = t_span[0] t_end = t_span[1] y = np.array(y0) t_values = [t] y_values = [y.copy()] a = [1/5, 3/10, 4/5, 8/9, 1, 1] b = [ [1/5], [3/40, 9/40], [44/45, -56/15, 32/9], [19372/6561, -25360/2187, 64448/6561, -212/729], [9017/3168, -355/33, 46732/5247, 49/176, -5103/18656], [35/384, 0, 500/1113, 125/192, -2187/6784, 11/84] ] c = [1/5, 3/10, 4/5, 8/9, 1, 1] e = [35/384, 0, 500/1113, 125/192, -2187/6784, 11/84, 0] d = [5179/57600, 0, 7571/16695, 393/640, -92097/339200, 187/2100, 1/40] while t < t_end: if t + h > t_end: h = t_end - t k = [f(t, y)] for i in range(1, 6): ti = t + a[i-1] * h yi = y + h * sum(b[i][j] * k[j] for j in range(i)) k.append(f(ti, yi)) # 计算五阶解 y5 = y + h * sum(d[i] * k[i] for i in range(6)) # 计算四阶解 y4 = y + h * sum(e[i] * k[i] for i in range(6)) # 估计误差 error = np.linalg.norm(y5 - y4, np.inf) # 调整步长 tol = 1e-6 if error > tol: h *= 0.9 * (tol / error)**0.2 # 更新时间步 t += h y = y5 t_values.append(t) y_values.append(y.copy()) return t_values, y_values # 示例 ODE def f(t, y): return -2 * t * y # 初始条件 y0 = [1.0] # 时间区间 t_span = [0, 2] # 调用 Dormand-Prince 方法 t_vals, y_vals = dormand_prince(f, t_span, y0, 0.1) ``` 上述代码实现了基本的 Dormand-Prince 方法,并用于求解了一个简单的 ODE。在实际应用中,通常会使用更复杂的自适应步长控制策略和误差估计方法来进一步优化性能和精度。 ### 优点 - **高精度**:Dormand-Prince 方法提供五阶精度的解,适合需要较高精度的应用。 - **自适应步长控制**:通过比较四阶和五阶解之间的差异,可以动态调整步长以满足指定的误差容限。 - **高效性**:由于其嵌套结构,Dormand-Prince 方法能够在较少的函数评估次数下达到较高的精度。 ### 应用领域 - **物理模拟**:用于求解经典力学、流体力学等领域的 ODE。 - **控制系统**:在控制理论中,用于分析和设计控制系统。 - **生物数学**:用于建模种群动态、流行病传播等生物过程。 - **金融工程**:用于求解随机微分方程(SDEs)的数值解,尽管此时通常需要结合伊藤积分或其他随机积分方法[^1]。 ### 总结 Dormand-Prince 方法是一种高效的数值积分技术,广泛应用于科学计算和工程领域。它的自适应步长控制和高精度特性使其成为求解非刚性 ODE 的首选方法之一。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值