2019计蒜之道复赛A:外教Michale变身大熊猫【树状数组+dp】

题目:

题目在这里~~~

分析:

按照题意,只需要找到最长上升子序列的数量和每个数对最长上升子序列的贡献次数即可,可以二分找到经过每个数的最长上升子序列的长度,但这样不好统计数量;考虑dp,定义dp[i]为以第i个数结尾的最长上升子序列的长度,DP[i]为其数量,容易想到转移方程:dp[i] = max{dp[j],0<j<i && a[j] < a[i]} + 1,DP[i] = sum{DP[j],0<j<i && dp[j] = dp[i]-1},线段树维护区间最大值及其数量即可快速转移,每次都是在前缀上查询,也可以用树状数组维护;再从后到前来一遍,就可以求出经过每个点的最长上升子序列的长度和数量

代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int mod = 998244353;
const int maxn = 5e5+55;
struct node{
    LL len,num;
}tr[maxn];
int n,m,a[maxn],c[maxn];
node pre[maxn],cur[maxn];
inline int lowbit(int x){
    return x&(-x);
}
void add(int x,node e){
    while(x <= m){
       if(tr[x].len == e.len) tr[x].num = (tr[x].num+e.num)%mod;
       else if(tr[x].len < e.len){
        tr[x].len = e.len;
        tr[x].num = e.num;
       }
       x += lowbit(x); 
    }
}
node query(int x){
    node res = {0,0};
    while(x > 0){
        if(res.len == tr[x].len) res.num = (res.num+tr[x].num)%mod;
        else if(res.len < tr[x].len){
            res.len = tr[x].len;
            res.num = tr[x].num;
        }
        x -= lowbit(x);
    }
    return res;
}
LL qpow(LL a,LL x){
    LL res = 1;
    while(x){
        if(x&1) res = res * a % mod;
        a = a * a % mod;
        x >>= 1;
    }
    return res;
}
int main(){
    cin >> n;
    for(int i = 0;i < n; ++i) cin >> a[i],c[i] = a[i];
    sort(c,c+n); m = unique(c,c+n) - c;
    for(int i = 0;i < n; ++i) a[i] = lower_bound(c,c+m,a[i])-c+1;
    for(int i = 0;i < n; ++i){
        pre[i] = query(a[i]-1);
        if(++pre[i].len == 1) pre[i].num = 1;
        add(a[i],pre[i]);
    }
    for(int i = 0; i < n; ++i) a[i] = m-a[i]+1;  //反转序号,方便树状数组更新和查询
    memset(tr,0,sizeof(tr));
    node ans = {0,0};                 //整个数组的最长上升子序列的长度及数量
    for(int i = n-1; ~i; --i){
        cur[i] = query(a[i]-1);
        if(++cur[i].len == 1) cur[i].num = 1;
        add(a[i],cur[i]);
        if(ans.len == cur[i].len) ans.num = (ans.num + cur[i].num)%mod;
        else if(ans.len < cur[i].len) ans = cur[i];
    }
    LL inv = qpow(ans.num,mod-2);
    for(int i = 0;i < n; ++i){
        if(pre[i].len+cur[i].len==ans.len+1) {
            printf("%lld ",pre[i].num*cur[i].num%mod*inv%mod);
        }
        else printf("0 ");
    }
    return 0; 
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用熵权TOPSIS法的Python代码示例: ```python import numpy as np import pandas as pd # 计算熵权 def entropyWeight(data): p = data / data.sum() entropy = (-p * np.log2(p)).sum() weight = (1 - entropy) / (len(data) - 1) return weight # 极小型指标转为极大型 def dataDirection_1(data): return 1 / data # 区间型指标转为极大型 def dataDirection_3(data, a, b, c, d): return (data - a) / (b - a) * (d - c) + c # 计算得分并排序(人工赋权重) def topsis(data, weight=None): Z = pd.DataFrame(\[data.max(), data.min()\], index=\['正理想解', '负理想解'\]) # 最优最劣方案(最大值Z^+ 和 最小值) weight = entropyWeight(data) if weight is None else np.array(weight) Result = data.copy() Result\['正理想解'\] = np.sqrt(((data - Z.loc\['正理想解'\]) ** 2 * weight).sum(axis=1)) # 评价对象与最大值的距离 Result\['负理想解'\] = np.sqrt(((data - Z.loc\['负理想解'\]) ** 2 * weight).sum(axis=1)) # 评价对象与最小值的距离 Result\['综合得分指数'\] = Result\['负理想解'\] / (Result\['负理想解'\] + Result\['正理想解'\]) # 综合得分指数 Result\['排序'\] = Result.rank(ascending=False)\['综合得分指数'\] return Result, Z, weight # 例题数据处理 data = pd.DataFrame({ '人均专著': \[0.1, 0.2, 0.4, 0.9, 1.2\], '生师比': \[5, 6, 7, 10, 2\], '科研经费': \[5000, 6000, 7000, 10000, 400\], '逾期毕业率': \[4.7, 5.6, 6.7, 2.3, 1.8\] }, index=\['院校' + i for i in list('ABCDE')\]) # 极小型指标转为极大型 minimum_list = dataDirection_1(data.loc\[:, "逾期毕业率"\]) minimum_array = np.array(minimum_list) minimum_4f = np.round(minimum_array, 6) # 区间型指标转为极大型 maximum_list = dataDirection_3(data.loc\[:, "生师比"\], 5, 6, 2, 12) maximum_array = np.array(maximum_list) maximum_4f = np.round(maximum_array, 6) # 指标正向化结果 index_Isotropy = pd.DataFrame() index_Isotropy\["人均专著"\] = data\["人均专著"\] index_Isotropy\["生师比"\] = maximum_4f index_Isotropy\["科研经费"\] = data\["科研经费"\] index_Isotropy\["逾期毕业率"\] = minimum_4f # 人工赋权重的结果 weight = \[0.2, 0.3, 0.4, 0.1\] Result, Z, weight = topsis(index_Isotropy, weight) ``` 这段代码实现了熵权TOPSIS法的计算过程,包括指标转换、熵权计算、得分计算和排序。最终的结果存储在`Result`中,最优最劣方案存储在`Z`中,权重存储在`weight`中。 #### 引用[.reference_title] - *1* *2* *3* [TOPSIS(优劣解距离法)【附Python实现代码及可视化代码】](https://blog.csdn.net/Michale_L/article/details/127832863)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值