[csa round#1]Number Elimination——动态规划+计数

题目大意:

你有\(n\)个方块排成一排,每个方块有一个权值\(a_i\),你每次可以选择一个二元组\((x,y) x<y\),并消除x和y中权值较小的那个方块,如果二者权值相同则消除标号较小的那个,产生\(max(a_x,a_y)\)的费用。你每次选择的二元组中不能选择已经被消除的方块。最后这一排方块只会剩下一个,游戏目标是使费用最少。
求可以使费用最小的方案数。

思路:

为了使费用最小,可以发现相同的数一定是要在一起消,直到只剩一个。
同时对于不同的数之间,我们要消除一个数的话,这个数必定只剩下一个,并且比这个数小的数都要在之前消完。
不同的种类一定是从小到大的顺序消完,于是我们设dp[i]为前i个种类消完的方案数,每一次将一个种类添加进去来转移。
这里需要预处理一个种类自身消除的方案数\(f[i]\)(i为集合大小)\(=f[i-1]\times i \times (i-1)/2\)
于是在dp[i]的时候枚举第i个种类的物品在i-1种最后一个消完之前消完的数量j,用隔板法来计算前j个放置的位置,可得dp方程为:
\[dp_{i}=\sum_{j=0}^{sz_i-1}\times f_{i-1}\times {sum_{i-1}+j-1\choose j}\times(sz_i-j)\]
直接转移即可。

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<endl
typedef long long ll;

using namespace std;

void File(){
    freopen("out.in","r",stdin);
    freopen("out.out","w",stdout);
}

template<typename T>void read(T &_){
    T __=0,mul=1; char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')mul=-1;
        ch=getchar();
    }
    while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    _=__*mul;
}

const int maxn=1e5+10;
const ll mod=1e9+7;
int n,a[maxn],b[maxn],tot,cnt[maxn];
ll fac[maxn],ifac[maxn],f[maxn],dp[maxn],sum[maxn];

ll qpow(ll x,ll y){
    ll ret=1; x%=mod;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ret;
}

ll C(ll x,ll y){return fac[x]*ifac[y]%mod*ifac[x-y]%mod;}

int main(){
//  File();
    read(n);
    REP(i,1,n)read(a[i]),b[++tot]=a[i];

    sort(b+1,b+tot+1);
    tot=unique(b+1,b+tot+1)-b-1;
    REP(i,1,n)a[i]=lower_bound(b+1,b+tot+1,a[i])-b;

    fac[0]=1;
    REP(i,1,n)fac[i]=fac[i-1]*i%mod;
    ifac[n]=qpow(fac[n],mod-2);
    DREP(i,n-1,0)ifac[i]=ifac[i+1]*(i+1)%mod;

    REP(i,1,n)++cnt[a[i]];

    f[0]=1;
    ll inv2=qpow(2,mod-2);
    REP(i,1,n)f[i]=f[i-1]*i%mod*(i+1)%mod*inv2%mod;

    dp[1]=f[cnt[1]-1];
    REP(i,2,tot){
        sum[i-1]=sum[i-2]+cnt[i-1];
        REP(j,0,cnt[i]-1)
            dp[i]=(dp[i]+dp[i-1]*C(sum[i-1]+j-1,j)%mod*(cnt[i]-j)%mod)%mod;
        dp[i]=dp[i]*f[cnt[i]-1]%mod;
    }

    printf("%lld\n",dp[tot]);
    return 0;
}

转载于:https://www.cnblogs.com/ylsoi/p/9838713.html

To convert a string representing a number in base `k` to its decimal (base 10) equivalent in C++, the core idea involves parsing each character of the string, mapping it to its corresponding numeric value, and then applying positional notation to compute the final decimal value. The algorithm typically processes the string from left to right or right to left, multiplying each digit by the appropriate power of the base. Here is a standard implementation: ```cpp #include <iostream> #include <string> #include <cmath> int charToValue(char c) { if (std::isdigit(c)) return c - '0'; return std::tolower(c) - 'a' + 10; } char valueToChar(int value) { if (value < 10) return '0' + value; return 'a' + value - 10; } long long convertToDecimal(const std::string& num, int base) { long long result = 0; for (char c : num) { int value = charToValue(c); result = result * base + value; } return result; } ``` ### Explanation 1. **Character to Value Mapping**: The function `charToValue` converts a character (`char`) into its corresponding integer value. For instance, `'A'` or `'a'` maps to 10 in hexadecimal notation. This supports bases up to 36[^1]. 2. **Conversion Logic**: The `convertToDecimal` function iterates through the string, computing the decimal value by repeatedly multiplying the current result by the base and adding the value of the next digit. This approach avoids the need to compute powers explicitly, which leads to better performance[^2]. ### Optimization Considerations 1. **Avoiding Redundant Checks**: In performance-sensitive applications, ensure that character validation (e.g., checking if a character is a valid digit in the given base) is done before processing. This avoids redundant checks during the actual conversion process[^1]. 2. **Efficient Character Handling**: Use direct ASCII arithmetic to convert characters to their numeric values instead of using slower alternatives like `std::stoi` or `std::stringstream`[^2]. 3. **Precomputed Lookup Table**: For bases that are known at compile time or for repeated conversions, consider using a precomputed lookup table for character-to-value mappings to reduce computation overhead[^1]. Here is an optimized version using a lookup table: ```cpp #include <iostream> #include <string> #include <array> constexpr int base = 16; constexpr int lookupTableSize = 256; std::array<int, lookupTableSize> createLookupTable() { std::array<int, lookupTableSize> table = {}; for (int i = 0; i < lookupTableSize; ++i) { char c = static_cast<char>(i); if (std::isdigit(c)) table[i] = c - '0'; else if (std::isxdigit(c)) table[i] = std::tolower(c) - 'a' + 10; else table[i] = -1; // Invalid character } return table; } const auto lookupTable = createLookupTable(); long long convertToDecimalOptimized(const std::string& num) { long long result = 0; for (char c : num) { int value = lookupTable[static_cast<unsigned char>(c)]; result = result * base + value; } return result; } ``` ### Key Optimizations 1. **Precomputed Lookup Table**: The `lookupTable` is computed at compile time and provides constant-time access to character-to-value mappings, improving performance during runtime. 2. **Elimination of Function Calls**: By embedding the character-to-value logic directly within the conversion function, the overhead of separate function calls is eliminated. These optimizations are particularly relevant in game development and high-performance computing, where tools and data-processing pipelines may involve repeated conversions and require efficient implementations. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值