“华为杯“ 武汉大学21级新生程序设计竞赛(补题)

这篇博客探讨了两种算法在信息技术问题中的应用。第一部分介绍了如何使用线段树解决区间最大编号之和的问题,通过预处理和二分查找优化了查询效率。第二部分讨论了哈希在字符串对称子串计数中的作用,强调了避免哈希冲突的重要性,并提供了一种解决方案。文章展示了在算法设计中如何结合数据结构和数学技巧来优化问题的解答。

和谐之树 · 改

题意:
给定n,设p为对区间【1,n】建线段树的时候的最大编号,对于所有的k ∈【L,R】,求【1,K】的最大编号之和。
做法:
稍微提一下对于区间【1,K】的最大编号,首先找到2的最高幂次cnt < K,求出K与 pow(2,cnt + 1)的差c,然后多想想就能发现c对剩余编号的影响,如果右子树有值,那么左子树一定是满的,这样就可以不断地对c /= 2,求出最大编号了。
很显然这个答案具有单调性,二分打表处理一下发现1 ~ 1e18中最大编号只有1850个。所以可以预处理一下这1850个区间前缀和,然后二分logn的查询sum(l - 1) 与sum( r ),就能得到区间【L,R】的和了。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 5, mod = 998244353;
struct node{
    int l, r;
    int val, pos;
}a[N];
unordered_map <int, node> f;
int get(int n)
{
    int cnt = 0;
    int num = n;
    while(num) {
        cnt++;
        num >>= 1;
    }
    int c = n - (1ll << (cnt-1) );
    int ans = (1ll << cnt) - 1;
    int mi = (1ll << (cnt - 1));
    while(c > 1) {
        ans += mi;
        mi /= 2;
        c /= 2;
    }
    if (c) ans+=2;
    return ans;
}
int bsh(int l, int r, int k)
{
    while(l < r)
    {
        int mid = (l + r + 1) >> 1;
        if (get(mid) <= k) l = mid;
        else r = mid - 1;
    }
    return l;
}
int sum(int n)
{
    if (n <= 0) return 0;
    int kk = get(n);
    node p = f[kk];
    int ret = a[p.pos - 1].val;
    for (int l = p.l, r; l <= n; l = r + 1) {
        int val = get(l);
        r = bsh(l, n, val);
        ret = (ret + (r - l + 1) % mod * (val % mod) % mod) % mod;
    }
    return ret;
}
void solve()
{
    int L, R;
    scanf("%lld%lld", &L, &R);
    printf("%lld\n", ( ( (sum(R) - sum(L - 1)) % mod) + mod) % mod);
}
signed main()
{
    int n = 1000000000000000000ll;
    int cnt = 0;
    for (int l = 1, r; l <= n; l = r + 1) {
        int val = get(l);
        r = bsh(l, n, val);
        cnt++;
        f[val] = node{l, r, val, cnt};


        a[cnt].l = l;
        a[cnt].r = r;
        a[cnt].val = (a[cnt - 1].val + (r - l + 1) % mod * (val % mod) % mod) % mod;
    }
    
    int tt = 1;
    cin >> tt;
    while (tt--) solve();
    return 0;
}

仓鼠与炸弹

题意:
在字符串s中,对于每个长度为m的子串,求他的对称串有多少个,输出所有的对称串的和。
做法:
要不断的匹配,很显然是哈希。
这题最大坑在于构造出了卡哈希的数据。单单自然溢出取模,底数为某个质数,会发生哈希冲突。
可以对某个大质数p取模,底数选择两个不同的质数。这样是能过这题的,没有自然溢出了,很多地方记得要对p取模。
如果非要自然溢出取模,可以选择一个质数,另一个质数选择2,这样不会被卡,至于另一个为什么选择2,我也不清楚,试了很多次其他的质数,都不行。。。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 5, mod = 1e9 + 7;
int p1[N], p2[N], fr[N], fl[N];
int fll[N], frr[N];
char s[N];
struct node {
    int x, y;
    bool operator < (const node &k) const 
    {
        if (x != k.x) return x < k.x;
        return y < k.y;
    }
};
node get_hou(int l, int r)
{
    int len = r - l + 1;
    int h1 = ((fr[l] - fr[r + 1] * p1[len] % mod) % mod + mod) % mod;
    int h2 = ((frr[l] - frr[r + 1] * p2[len] % mod) % mod + mod) % mod;
    return node{h1, h2};
}
node get_qian(int l, int r)
{
    int len = r - l + 1;
    int h1 = ((fl[r] - fl[l - 1] * p1[len] % mod) % mod + mod) % mod;
    int h2 = ((fll[r] - fll[l - 1] * p2[len] % mod) % mod + mod) % mod;
    return node{h1, h2};
}
node r[N];
map<node, int> f;
void solve()
{
    int n, m;
    cin >> n >> m;
    scanf("%s", s + 1);
    p1[0] = p2[0] = 1;
    for (int i = 1; i <= 100000; i++) 
    {
        p1[i] = p1[i - 1] * 131 % mod;
        p2[i] = p2[i - 1] * 31 % mod;
    }
    for (int i = n; i >= 1; i--) 
    {
        fr[i] = (fr[i + 1] * 131 % mod + (s[i] - 'a' + 1)) % mod;
        frr[i] = (frr[i + 1] * 31 % mod + (s[i] - 'a' + 1)) % mod;
    }
    for (int i = 1; i <= n; i++) 
    {
        fl[i] = (fl[i - 1] * 131 % mod + (s[i] - 'a' + 1)) % mod;
        fll[i] = (fll[i - 1] * 31 % mod + (s[i] - 'a' + 1)) % mod;
    }

    for (int i = n; i - m + 1 >= m + 1; i--) {
        r[i] = get_hou(i - m + 1, i);
        f[r[i]]++;
    }


    int ans = 0;
    for (int i = 1; i + m - 1 <= n - m; i++) 
    {
        ans += f[get_qian(i, i + m - 1)];
        f[r[i + 2 * m - 1]]--;
    }
    cout << ans;
}
signed main()
{
    int tt = 1;
    // cin >> tt;
    while (tt--) solve();
    return 0;
}
**高校专业实习管理平台设计与实现** 本设计项目旨在构建一个服务于高等院校专业实习环节的综合性管理平台。该系统采用当前主流的Web开发架构,基于Python编程语言,结合Django后端框架与Vue.js前端框架进行开发,实现了前后端逻辑的分离。数据存储层选用广泛应用的MySQL关系型数据库,确保了系统的稳定性和数据处理的效率。 平台设计了多角色协同工作的管理模型,具体包括系统管理员、院系负责人、指导教师、实习单位对接人以及参与实习的学生。各角色依据权限访问不同的功能模块,共同构成完整的实习管理流程。核心功能模块涵盖:基础信息管理(如院系、专业、人员信息)、实习过程管理(包括实习公告发布、实习内容规划、实习申请与安排)、双向反馈机制(单位评价与学生反馈)、实习支持与保障、以及贯穿始终的成绩评定与综合成绩管理。 在技术实现层面,后端服务依托Django框架的高效与安全性构建业务逻辑;前端界面则利用Vue.js的组件化特性与LayUI的样式库,致力于提供清晰、友好的用户交互体验。数据库设计充分考虑了实习管理业务的实体关系与数据一致性要求,并保留了未来功能扩展的灵活性。 整个系统遵循规范的软件开发流程,从需求分析、系统设计、编码实现到测试验证,均进行了多轮迭代与优化,力求在功能完备性、系统性能及用户使用体验方面达到较高标准。 **核心术语**:实习管理平台;Django框架;MySQL数据库;Vue.js前端;Python语言。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值