2023NOIP A层联测18-划分

这篇具有很好参考价值的文章主要介绍了2023NOIP A层联测18-划分。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目

字符串编号从 1 1 1 开始。

n = k n=k n=k,最大值很好求,方案数就是 1 1 1

若前 k k k 个都没有 1 1 1,设第一个 1 1 1 出现的位置为 m m m,最大值是选 m m m 开始的后缀,划分方案是在前 m m m 个空位插大于等于 k − 1 k-1 k1 个隔板,用组合数可以轻松求出。

否则,最大值一定是选长度为 n − k + 1 n-k+1 nk+1 的子串 a a a,剩下每个数单独为一个段。

现在考虑怎样选这样的子串使答案最大。显然选二进制最大的。

证明:设二进制最大的子串为 a a a,另一个不是最大的子串为 b b b,设 1 1 1 的总数为 x x x。由于 1 1 1 的总数始终不变,即证明: x − popcount(a) ⁡ + a ≥ x − popcount ⁡ ( b ) + b x-\operatorname{popcount(a)}+a\ge x-\operatorname{popcount}(b)+b xpopcount(a)+axpopcount(b)+b。化简得 a − popcount(a) ⁡ ≥ b − popcount ⁡ ( b ) a-\operatorname{popcount(a)}\ge b-\operatorname{popcount}(b) apopcount(a)bpopcount(b)

f ( n ) = n − popcount ⁡ ( n ) f(n)=n-\operatorname{popcount}(n) f(n)=npopcount(n),即证它是不减函数。对其差分得 popcount ⁡ ( n ) − popcount ⁡ ( n + 1 ) + 1 \operatorname{popcount}(n)-\operatorname{popcount}(n+1)+1 popcount(n)popcount(n+1)+1,显然若 n + 1 n+1 n+1 popcount ⁡ ( n ) \operatorname{popcount}(n) popcount(n) 要么增加 1 1 1(此时 n n n 为偶数时取等),要么减少,得证。

由上面结论和取等条件,我们要做的是:先找最大的子串,然后统计前 n − k n-k nk 个相同的子串个数,即为方案数。

问题转换为求长度为 n − k + 1 n-k+1 nk+1 的字典序最大的子串。

这个问题可以用二分+哈希解决。

我们有 k k k 个子串待比较,令第一个子串是当前的最大子串,后面更新。

对于当前最大子串 s s s 和左端点为 i i i 的子串 t t t,若 t t t 可以更新 s s s,即 t > s t>s t>s,则 s s s t t t 会有一段公共前缀(可能没有),接下来一个数字 t t t 1 1 1 s s s 0 0 0,我们想要快速求出公共前缀的长度,这里就二分长度 m i d mid mid,如果二者长度为 m i d mid mid 的子串不相等,就把 m i d mid mid 变小,否则变大;快速判断子串是否相等可以用哈希。

时间复杂度为 O ( k log ⁡ ( n − k ) ) O(k\log(n-k)) O(klog(nk))

具体实现看代码文章来源地址https://www.toymoban.com/news/detail-719780.html

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353,mod1=1e9+7;
const int N=2e6+1;
int n,k,sum[N];
char a[N];
ll f[N],inv[N],pw1[N],pw2[N],a1[N],a2[N];
ll ksm(ll a,ll b)
{
    ll ans=1;
    while(b){
        if(b&1) ans=ans*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}
struct node
{
    int fl,son[2];
}tr[2000001];
pair<ll,ll> geth(int l,int r)
{
    return make_pair((a1[r]-a1[l-1]*pw1[r-l+1]%mod+mod)%mod,(a2[r]-a2[l-1]*pw2[r-l+1]%mod1+mod1)%mod1);
}
int main()
{
    freopen("divide.in","r",stdin);
    freopen("divide.out","w",stdout);
    scanf("%d%d%s",&n,&k,a+1);
    pw1[0]=pw2[0]=1;
    for(int i=1;i<=n;i++) pw1[i]=pw1[i-1]*2%mod,pw2[i]=pw2[i-1]*2%mod1;
    for(int i=1;i<=n;i++) a1[i]=(a1[i-1]*2+a[i]-48)%mod,a2[i]=(a2[i-1]*2+a[i]-48)%mod1,sum[i]=sum[i-1]+a[i]-48;
    int fl=0;
    for(int i=1;i<=k;i++) if(a[i]==49){fl=1;break;}
    if(n==k){
        int x=0;
        for(int i=1;i<=n;i++) x+=a[i]-48;
        printf("%d 1",x);
    }
    else if(!fl){
        int m=0;
        while(m<n&&a[m+1]=='0') m++;
        if(m==n) m--;
        f[0]=1;
        for(int i=1;i<=n;i++) f[i]=f[i-1]*i%mod;
        inv[n]=ksm(f[n],mod-2);
        for(int i=n-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
        ll x=0,ans=0;
        for(int i=m+1;i<=n;i++) x=(x*2+a[i]-48)%mod;
        for(int i=k-1;i<=m;i++) ans=(ans+f[m]*inv[i]%mod*inv[m-i])%mod;
        printf("%lld %lld",x,ans);
    }
    else{
        int maxi=1,ans=0;
        for(int i=2;i<=k;i++){
            int l=0,r=n-k+1,ans=l;
            while(l<=r){
                int mid=l+r>>1;
                if(geth(i,i+mid-1)!=geth(maxi,maxi+mid-1)) r=mid-1;
                else l=mid+1,ans=mid;
            }
            if(a[maxi+ans]<a[i+ans]) maxi=i;
        }
        for(int i=1;i<=k;i++) if(geth(i,i+n-k-1)==geth(maxi,maxi+n-k-1)) ans++;
        printf("%lld %d",(geth(maxi,maxi+n-k).first+sum[maxi-1]+sum[n]-sum[maxi+n-k])%mod,ans);
    }
}

到了这里,关于2023NOIP A层联测18-划分的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • P1025 [NOIP2001 提高组] 数的划分(dfs+剪枝 or dp)

    思路:暴力枚举搜索,不过要优雅剪枝一下下 1:处理重复情况--我们只需要然后方取值从前往后的时候呈现递增(可以相等,即不递减) 2:剪枝--基于上思想,剩下的“盘子”里面的数至少都大于等于当前“盘子”的数,所以我们取完当前盘子的数完,就可判断--剩下的盘子

    2024年02月14日
    浏览(26)
  • LeetCode-763. 划分字母区间【贪心 哈希表 双指针 字符串】

    给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。 注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。 返回一个表示每个字符串片段的长度的列表。 示例 1: 输入:s = “ababcbacadefegdehijhklij” 输

    2024年04月10日
    浏览(37)
  • 【洛谷 P1003】[NOIP2011 提高组] 铺地毯 题解(数组+贪心算法)

    为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯。一共有 n n n 张地毯,编号从 1 1 1 到 n n n 。现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上

    2023年04月24日
    浏览(34)
  • 2023-8-26 字符串哈希

    题目链接:字符串哈希

    2024年02月11日
    浏览(25)
  • 【2023】LeetCode HOT 100——哈希

    🔗 原题链接:

    2024年02月12日
    浏览(29)
  • 划分字母区间【贪心算法】

    划分字母区间 给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。 注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。返回一个表示每个字符串片段的长度的列表。 参考下图: 1.确定每个元素的最

    2024年02月10日
    浏览(38)
  • 区块链:哈希算法与一致性哈希算法

    本篇主要介绍区块链中常用到的哈希算法。 1 哈希算法 1.1 定义及特性   哈希算法是指通过哈希函数(Hash Function)对任意长度的输入数据(比如文件、消息、数字等)进行转换,生成一个固定长度的哈希值(Hash Value)的过程。   在区块链中,哈希算法常用于区块验证及安全性保

    2024年02月17日
    浏览(51)
  • 多校联测11 THUSC

    题目大意 有 n n n 个人参加 T H U S C THUSC T H U SC ,第 i i i 个人算法场和工程场的成绩分别为 a i a_i a i ​ 和 b i b_i b i ​ ,保证不存在两个人两项成绩都相同。 现在招办想给他们排个名。一个合理的排名方案是分别给算法场和工程场一个正的权重 x , y x,y x , y ,然后按照 a i x

    2024年02月07日
    浏览(25)
  • 代码随想录-哈希表02 第454题.四数相加II&383. 赎金信&第15题. 三数之和&第18题. 四数之和

    第454题.四数相加II 第454题.四数相加II 条件:四个数组中分别取一个,相加和为0,求满足条件的元组个数 思路使用1个map,mapA保存 s1 s2中相加和及其出现次数 遍历s3 s4,去判断是否满足 0 - (s3[i] + s4[j]) 在mapA中,并统计出现次数 383. 赎金信 383. 赎金信 题目要求,s1 是否能由s

    2024年02月12日
    浏览(31)
  • 【算法】双指针划分思想妙解移动零

    Problem: 283. 移动零 首先我们来讲一下本题的思路 本题主要可以归到【数组划分/数组分块】这一类的题型。我们将一个数组中的所有元素划分为两段区间, 左侧是非零元素,右侧是零元素 那解决这一类的题我们首先想到的就是【双指针算法】,学习过C语言的同学应该就可以

    2024年02月12日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包