MUTC7 C - Dragon Ball 单调队列dp

文章详细介绍了如何运用单调队列和动态规划算法解决一个关于龙珠收集的问题。通过分析每批龙珠出现的位置和移动成本,优化收集策略以最小化总体力消耗。

Dragon Ball

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1680    Accepted Submission(s): 614


Problem Description
Sean has got a Treasure map which shows when and where the dragon balls will appear. some dragon balls will appear in a line at the same time for each period.Since the time you got one of them,the other dragon ball will disappear so he can only and must get one Dragon ball in each period.Digging out one ball he will lose some energy.Sean will lose |x-y| energy when he move from x to y.Suppose Sean has enough time to get any drogan ball he want in each period.We want to know the minimum energy sean will lose to get all period’s dragon ball.
 

Input
In the first line a number T indicate the number of test cases.Then for each case the first line contain 3 numbers m,n,x(1<=m<=50,1<=n<=1000),indicate m period Dragon ball will appear,n dragon balls for every period, x is the initial location of sean.Then two m*n matrix. For the first matrix,the number in I row and J column indicate the location of J-th Dragon ball in I th period.For the second matrix the number in I row and J column indicate the energy sean will lose for J-th Dragon ball in I-th period.
 

Output
For each case print a number means the minimum energy sean will lose.
 

Sample Input
  
1 3 2 5 2 3 4 1 1 3 1 1 1 3 4 2
 

Sample Output
  
8
 

Author
FZU
 

Source
 

Recommend
zhuyuanchen520

------------

单调队列+DP


设dp[i][j]表示第i批龙珠中取第j个需要花费的最小体力。

dp[i][j] = min{ dp[i-1][k] + abs(pos[i-1][k]-pos[i][j]) } + cost[i][j];

如果枚举k的话总复杂度位m*n*n,会超时。

可以看出若每个状态只由上一层位置在其左边的状态的转移而来的话:  

dp[i][j]

min { dp[i-1][k] + pos[i][j] - pos[i-1][k] } + cost[i][j]

= min { dp[i-1][k] - pos[i-1][k] } + pos[i][j] + cost[i][j]

dp[i-1][k]-pos[i-1][k]是个确定的值,就是相当于求位置在pos[i][j]左边的上一层状态中值最小的,可以用个单调队列维护。由右边转移来的类似,再处理一遍右边转移来的取最优。

因为要对同一层的点排序,所以总复杂度是m*n*logn。

-----------

/** head-file **/

#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <list>
#include <set>
#include <map>
#include <algorithm>

/** define-for **/

#define REP(i, n) for (int i=0;i<int(n);++i)
#define FOR(i, a, b) for (int i=int(a);i<int(b);++i)
#define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i)
#define REP_1(i, n) for (int i=1;i<=int(n);++i)
#define FOR_1(i, a, b) for (int i=int(a);i<=int(b);++i)
#define DWN_1(i, b, a) for (int i=int(b);i>=int(a);--i)
#define REP_N(i, n) for (i=0;i<int(n);++i)
#define FOR_N(i, a, b) for (i=int(a);i<int(b);++i)
#define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i)
#define REP_1_N(i, n) for (i=1;i<=int(n);++i)
#define FOR_1_N(i, a, b) for (i=int(a);i<=int(b);++i)
#define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i)

/** define-useful **/

#define clr(x,a) memset(x,a,sizeof(x))
#define sz(x) int(x.size())
#define see(x) cerr<<#x<<" "<<x<<endl
#define se(x) cerr<<" "<<x
#define pb push_back
#define mp make_pair

/** test **/

#define Display(A, n, m) {                      \
    REP(i, n){                                  \
        REP(j, m) cout << A[i][j] << " ";       \
        cout << endl;                           \
    }                                           \
}

#define Display_1(A, n, m) {                    \
    REP_1(i, n){                                \
        REP_1(j, m) cout << A[i][j] << " ";     \
        cout << endl;                           \
    }                                           \
}

using namespace std;

/** typedef **/

typedef long long LL;

/** Add - On **/

const int direct4[4][2]={ {0,1},{1,0},{0,-1},{-1,0} };
const int direct8[8][2]={ {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int direct3[6][3]={ {1,0,0},{0,1,0},{0,0,1},{-1,0,0},{0,-1,0},{0,0,-1} };

const int MOD = 1000000007;
const int INF = 0x3f3f3f3f;
const long long INFF = 1LL << 60;
const double EPS = 1e-9;
const double OO = 1e15;
const double PI = acos(-1.0); //M_PI;

int n,m,s;
struct node{
    int local;
    int cost;
}a[55][1111];
int f[55][1111];
/** f[i][j]=min(f[i-1][k]+abs(a[i][j].local-a[i-1][k].local)+a[i][j].cost) **/
int head,tail;
int que[1111];
int dp(int i,int j,int k)
{
    return f[i-1][k]+abs(a[i][j].local-a[i-1][k].local)+a[i][j].cost;
}

bool cmp(node a,node b)
{
    return a.local<b.local;
}

int main()
{
    int T;
    cin>>T;
    while (cin>>n>>m>>s)
    {
        clr(f,INF);
        REP_1(i,n) REP_1(j,m)
            cin>>a[i][j].local;
        REP_1(i,n)
        {
            REP_1(j,m) cin>>a[i][j].cost;
            sort(a[i]+1,a[i]+m+1,cmp);
        }
        REP_1(i,m)
        {
            f[1][i]=abs(s-a[1][i].local)+a[1][i].cost;
        }
        FOR_1(i,2,n)
        {
            head=tail=0;
            int k=1;
            FOR_1(j,1,m)
            {
                while (k<=m&&a[i-1][k].local<=a[i][j].local)
                {
                    int t=dp(i,j,k);
                    while (head<tail&&dp(i,j,que[tail-1])>=t) tail--;
                    que[tail++]=k;
                    k++;
                }
                if (head<tail) f[i][j]=dp(i,j,que[head]);
            }
            head=tail=0;
            k=m;
            DWN_1(j,m,1)
            {
                while (k>=1&&a[i-1][k].local>a[i][j].local)
                {
                    int t=dp(i,j,k);
                    while (head<tail&&dp(i,j,que[tail-1])>=t) tail--;
                    que[tail++]=k;
                    k--;
                }
                if (head<tail) f[i][j]=min(f[i][j],dp(i,j,que[head]));
            }
        }
        int ans=INF;
        REP_1(i,m)
        {
            ans=min(ans,f[n][i]);
        }
        cout<<ans<<endl;
    }
    return 0;
}




<think>我们正在讨论如何通过软件仿真获取三元半导体合金(如InGaAs)的弯曲系数(bowing parameter)。弯曲系数描述了合金的禁带宽度等参数随组分变化的非线性程度,通常用二次函数的系数表示,即: $$E_g(x) = x E_g^{A} + (1-x) E_g^{B} - b x(1-x)$$ 其中$b$就是弯曲系数。 使用软件进行仿真的方法主要包括第一性原理计算和半导体器件仿真软件(TCAD)两种途径。下面我们将详细讨论这两种方法。 ### 1. **第一性原理计算软件** 这类软件基于量子力学基本原理,通过求解薛定谔方程来模拟材料的电子结构。常用的软件包有VASP、Quantum ESPRESSO、ABINIT等。具体步骤如下: **步骤1:构建结构模型** - 对于三元合金(如In$_{x}$Ga$_{1-x}$As),需要构建不同组分$x$的晶体结构模型。由于合金中原子排列是无序的,通常采用特殊准随机结构(SQS)来近似模拟无序态。 - 示例:使用Materials Studio或ASE(Atomic Simulation Environment)生成InGaAs的SQS超胞。以下是一个用ASE生成SQS的简化示例代码: ```python from ase.build import bulk from sqs import generate_sqs # 构建64原子的超胞(4x4x4) base = bulk('InAs', crystalstructure='zincblende', a=6.058) atoms = base.repeat((4,4,4)) # 生成组分为x=0.5的SQS结构 generate_sqs(atoms, {'In':0.5, 'Ga':0.5}, size=64) ``` **步骤2:电子结构计算** - 使用密度泛函理论(DFT)计算能带结构。由于标准DFT(如LDA、GGA)会低估带隙,推荐使用杂化泛函(如HSE06)或GW方法进行修正。 - 计算不同组分$x$下的带隙$E_g(x)$。 **步骤3:拟合弯曲系数** - 将计算得到的不同$x$对应的$E_g(x)$数据点,用二次函数拟合: $$E_g(x) = x E_g^{\text{InAs}} + (1-x) E_g^{\text{GaAs}} - b x(1-x)$$ - 拟合得到的二次项系数$b$即为弯曲系数。 **注意事项**:计算精度取决于泛函选择、k点网格密度和超胞大小。通常需要收敛性测试以确保结果可靠。 ### 2. **半导体器件仿真软件(TCAD)** 这类软件(如Sentaurus TCAD、Silvaco Atlas)通过求解半导体物理方程(泊松方程、载流子连续性方程等)来模拟器件特性,也可用于材料参数提取。 **步骤1:定义材料参数** - 在软件中建立In$_{x}$Ga$_{1-x}$As材料模型,输入基础参数: - 二元化合物参数:InAs和GaAs的禁带宽度$E_g$、电子亲和能$\chi$、有效质量$m^*$等。 - 弯曲系数初始估计值(可从文献获取,如InGaAs的$b \approx 0.477\text{ eV}$[^1])。 **步骤2:设置虚拟实验** - 构造简单的器件结构(如pn结或肖特基二极管),通过改变In组分$x$,仿真其电流-电压(I-V)或电容-电压(C-V)特性。 - 利用光学仿真模块(如Sentaurus DEVICE中的Optical Interface)模拟吸收光谱,提取不同组分下的禁带宽度$E_g(x)$。 **步骤3:参数提取与优化** - 将仿真得到的$E_g(x)$数据与二次函数模型拟合,优化弯曲系数$b$。 - 若仿真结果与实验数据不符,可通过参数校准工具(如Sentaurus Calibration)调整$b$值,直至匹配。 > **示例流程(Sentaurus TCAD)**: > 1. 在`material.cmd`中定义InGaAs合金模型: > ```tcl > Material = "InGaAs" { > Parameter = "BandGap" { > Val = x*0.36 + (1-x)*1.42 - 0.477*x*(1-x) # 单位:eV > } > ... > } > ``` > 2. 仿真不同$x$下的器件光学响应,提取$E_g$(吸收系数$\alpha \propto \sqrt{h\nu - E_g}$)。 > 3. 使用`tfitter`工具拟合$b$值。 ### 仿真方法对比 | **方法** | **优点** | **缺点** | |------------------|-----------------------------------|-----------------------------------| | 第一性原理计算 | 无需实验数据,可探索新材料 | 计算成本高,需高性能计算集群 | | TCAD仿真 | 结合器件物理,结果更贴近应用 | 依赖初始参数,需实验数据验证 | ### 注意事项 - **组分均匀性假设**:仿真通常假设合金组分均匀,实际生长中可能存在偏析,需通过X射线衍射(XRD)或能谱仪(EDS)验证[^3]。 - **温度依赖性**:弯曲系数可能随温度变化,需在仿真中考虑温度模型(如Varshni方程)。 --- **相关问题** 1. 如何验证仿真得到的弯曲系数的准确性? 2. 弯曲系数是否与压力或应变有关? 3. 四元合金(如InGaAlAs)的弯曲参数如何通过TCAD仿真获取? </think>要使用软件仿真三元半导体合金(如InGaAs)的弯曲系数(bowing parameter),主要有以下两种技术路线: --- ### 1. **第一性原理计算软件** 通过量子力学模拟材料电子结构,计算不同组分下的禁带宽度: ```python # 使用VASP进行InGaAs带隙计算(伪代码) from ase.build import bulk from vasp import Vasp # 构建不同In组分的超胞 for x in [0.2, 0.5, 0.8]: # In组分比例 atoms = bulk('InGaAs', crystalstructure='zincblende', a=6.058*x + 5.653*(1-x)) # 维加德定律估算晶格常数 calc = Vasp(xc='HSE06', kpts=[4,4,4]) # 使用杂化泛函 atoms.calc = calc bandgap = calc.get_bandgap() # 获取禁带宽度 # 存储数据用于后续拟合 save_data(x, bandgap) # 拟合弯曲系数b fit_curve(E_g = x*E_g_InAs + (1-x)*E_g_GaAs - b*x*(1-x)) ``` **关键步骤**: - 使用**VASP/Quantum ESPRESSO**构建特殊准随机结构(SQS)模拟原子无序排列[^3] - 采用**HSE06或GW方法**解决带隙低估问题 - 通过**批量组分扫描**获取$E_g(x)$数据点 - 用二次函数拟合弯曲系数$b$(InGaAs典型值约0.48 eV) --- ### 2. **半导体TCAD仿真软件** 利用器件仿真平台提取光学/电学参数反推弯曲系数: ```tcl # Sentaurus TCAD命令示例 (InGaAs光电探测器仿真) Device { Material = InGaAs { Composition = x_In; # 设置In组分变量 BandGap = 0.36*x + 1.42*(1-x) - b*x*(1-x); # 弯曲模型 } Optics { Spectrum = AM1.5; # 光源设置 AbsorptionModel = Tauc; # 基于禁带宽度的吸收模型 } ParameterSweep { Var x_In = [0.1 -> 0.9 step 0.1]; # 扫描组分 Extract BandGap from OpticalResponse; # 从吸收边提取Eg } Calibration { Target Experimental_Eg; # 输入实验数据 Optimize b; # 优化弯曲系数 } } ``` **操作流程**: 1. 在**Sentaurus/Silvaco Atlas**中建立器件模型 2. 通过光学仿真(吸收光谱)或电学仿真(暗电流温度特性)提取$E_g$ 3. 使用**参数扫描+优化器**校准弯曲系数$b$ 4. 验证:比较仿真与实验的响应谱/IV曲线(如文献[2]的MUTC-PD器件) --- ### 关键考虑因素 | 方法 | 计算资源 | 精度 | 适用阶段 | |------------|------------|-----------|---------------| | 第一性原理 | 高 (HPC) | ±0.1 eV | 新材料设计 | | TCAD仿真 | 中等 | ±0.05 eV | 器件工艺验证 | > 📌 **注意事项**: > - 界面效应:衬底晶格失配(如Ge/Si衬底[^3])会引入应变,需在仿真中添加应变模型: > $$E_g^{\text{strained}} = E_g^{\text{bulk}} + \Delta E_{\text{hydrostatic}} + \Delta E_{\text{shear}}$$ > - 温度依赖性:结合Varshni方程$E_g(T) = E_0 - \alpha T^2/(T+\beta)$ > - 文献[1]指出高In组分需考虑载流子浓度对带隙的修正 --- **相关问题** 1. 如何验证仿真得到的弯曲系数准确性? 2. 衬底应变对InGaAs弯曲系数有何影响? 3. TCAD仿真中如何处理四元合金(如InGaAlAs)的弯曲参数?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值