ACM 2563 统计问题

本文介绍了一种通过递推公式解决数列问题的方法,并提供了一个C语言实现的例子。该方法利用了动态规划的思想,避免了重复计算,提高了计算效率。

 

分析:

A(N)表示第N步向上走的,B(N)表示第N步向左右走的

F(N) = A(N)+B(N)

A(N) = A(N-1)+B(N-1)

B(N) = 2*A(N-1) + B(N-1)

=>F(N) = 3*A(N-1) + 2*B(N-2) = 2*F(N-1) + A(N-1) = 2*F(N-1) + A(N-2) + B(N-2) = 2*F(N-1) + F(N-2)

 

 

#include <stdio.h>

int main()
{
    int i,N,T;
    double a[21];
    a[0]=1;
    a[1]=3;
    a[2]=7;
    for (i=3; i<=20; i++) {
        a[i]=2*a[i-1]+a[i-2];
    }
    
    scanf("%d",&T);
    while (T--) {
        scanf("%d",&N);
        printf("%.0f\n",a[N]);
    }
    return 0;
    
}
### ACM竞赛中的子串统计算法 在ACM竞赛中,字符串处理是一个重要的领域,其中涉及许多经典的子串统计问题和算法。以下是关于子串统计的一些常见算法及其应用: #### 1. **KMP算法** KMP(Knuth-Morris-Pratt)算法是一种高效的模式匹配算法,用于在一个主串 `S` 中查找是否存在某个子串 `P` 的所有出现位置[^1]。其核心思想是通过构建部分匹配表来减少不必要的字符比较次数。 ```cpp void computeLPSArray(string pat, int M, int* lps) { int len = 0; lps[0] = 0; int i = 1; while (i < M) { if (pat[i] == pat[len]) { len++; lps[i] = len; i++; } else { if (len != 0) { len = lps[len - 1]; } else { lps[i] = 0; i++; } } } } ``` 该算法的时间复杂度为 \(O(n)\),非常适合解决大规模数据下的子串匹配问题。 --- #### 2. **后缀数组** 后缀数组是对一个字符串的所有后缀按字典序排列的结果。它常被用来解决各种复杂的子串统计问题,比如最长公共前缀(LCP)、不同子串的数量等[^3]。 计算后缀数组的一个简单方法如下: ```cpp vector<int> suffix_array_construction(string s) { vector<pair<char, int>> a(s.size()); for(int i=0;i<s.size();i++)a[i]={s[i],i}; sort(a.begin(),a.end()); vector<int> order(s.size()),class_(s.size()); for(int i=0;i<s.size();i++)order[i]=a[i].second; class_[order[0]]=0; for(int i=1;i<s.size();i++){ if(a[i].first==a[i-1].first){ class_[order[i]]=class_[order[i-1]]; } else{ class_[order[i]]=class_[order[i-1]]+1; } } return order; } ``` 利用后缀数组可以快速找到字符串的不同子串数量以及它们的分布情况。 --- #### 3. **Z函数** Z函数也是一种强大的工具,能够在线性时间内完成某些特定类型的子串查询操作。给定一个字符串 `S` 和它的长度 `n`,定义 Z 数组使得对于每一个位置 `i` (\(1 \leq i < n\)),如果存在最大整数 \(z_i\) 满足从第 `i` 位开始的子串等于从开头开始的相同长度的子串,则返回这个值;否则返回零[^4]。 实现代码如下所示: ```cpp vector<int> z_function(const string& s) { int n = (int)s.length(); vector<int> z(n); for (int i = 1, l = 0, r = 0; i < n; ++i) { if (i <= r && z[i-l] < r-i+1) z[i] = z[i-l]; else { z[i] = max(0, r-i+1); while (i+z[i] < n && s[z[i]] == s[i+z[i]]) z[i]++; } if (i+z[i]-1 > r) l=i,r=i+z[i]-1; } return z; } ``` 此技术特别适合于那些需要频繁访问多个连续片段的应用场景之中。 --- #### 4. **Manacher's Algorithm** 马车夫算法专门针对回文子串检测进行了优化设计,在线性时间内解决了寻找最长中心扩展型回文序列这一难题[^2]。即使面对奇偶混合形式也毫无压力! 下面是其实现方式之一: ```cpp string preprocess(const string& s) { if (s.empty()) return "^$"; string ret = "^"; for(char c:s)ret+="#"+string(1,c); ret+="#$";return ret; } pair<string,int> manachers_algorithm(const string& str){ string T=preprocess(str);int n=T.size();vector<int>P(n,0);int C=0,R=0; for(int i=1;i<n-1;i++){//...省略具体逻辑... } // 返回最终结果结构体{palindrome,max_len} } ``` 上述四种主要方法构成了当前主流框架下应对各类挑战的基础理论支撑体系。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值