P13867 Unique Activities

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;

const int N=3e5+10,P=131;
ULL h[N],p[N];
char str[N];
//记录符合要求的字串的起始位置和长度
int res,st;

ULL get(int l,int r)
{
    return h[r]-h[l-1]*p[r-l+1];
}

int main()
{
    scanf("%s",str+1);
    int len=strlen(str+1);
    //预处理前缀和数组以及幂次
    p[0]=1;
    for(int i=1;i<=len;i++){
        h[i]=h[i-1]*P+str[i];
        p[i]=p[i-1]*P;
    }

    int l=0,r=len+1;
    while(l<=r){
        int mid=l+r>>1;
        //建立一个图,从哈希前缀映射出现次数和位置
        //一个循环统计字符串中长度为mid的字串的个数和起始位置(起始位置只记录第一个出现的即可)
        unordered_map<ULL,int> cnt,pos;
        for(int i=1;i+mid-1<=len;i++){
            ULL hs=get(i,i+mid-1);
            cnt[hs]++;
            if(!pos.count(hs)) pos[hs]=i; 
        }
        //然后去看仅出现一次的
        int p=len+1;
        bool ok=false;
        for(auto &[hs,c] : cnt){
            if(c==1){
                if(pos[hs]<p) p=pos[hs],ok=true;
            }
        }
        //真正的二分函数,上面相当于实现了一个check
        if(ok){
            res=mid,st=p;
            r=mid-1;
        }else l=mid+1;
    }

    for(int i=st;i<st+res;i++) putchar(str[i]);

    return 0;
}
哈希映射表,查找是否存在最小不重复字符串 最小不重复,那就是检查从小到大的所有字串 我学会了一种方法for(int i=1;i+mid-1<=n;i++)这就能遍历长度一定的字符串中的所有这个长度的字串了 以及哈希表可以实现一个hs映射多个位置,如本题就开了两个map,用一个hs映射start和cnt 以及二分查找函数的新写法,核心是先判断单调性,如果check函数不是很好写的话,就在二分函数中执行函数,用一个flag判断,同时,由于不是直接返回二分的线段长度,l=r时也要进行处理,故最后条件应该是l<=r
posted @ 2025-12-04 16:20  gosaky  阅读(0)  评论(0)    收藏  举报