省选联测 33

阿克了一车。除了我。

今天四个文件名貌似都是 Ubuntu 版本号。

张三

双指针。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
int n,k,ans;
char s[1000010];
int main(){
    scanf("%s%d",s+1,&k);n=strlen(s+1);
    int l=1,r=0,cnt=0;
    for(;r<=n;){
        while(r<=n&&cnt<=k){
            r++;
            if(s[r]=='1')cnt++;
        }
        ans=max(ans,r-l);
        while(cnt>k){
            if(s[l]=='1')cnt--;
            l++;
        }
    }
    printf("%d\n",ans);
    return 0;
}

李四

状压,设 \(dp_S\) 为还差 \(S\) 内的节点没有入住,那么转移考虑枚举最后一个入住的在哪里定居。这个节点满足要么可以登陆,要么和另一个没人的节点相邻。这样我们显然可以安排一个顺序使得全部都可以入住。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int n,m,k,s[25];
bool v[25];
unsigned int dp[1<<23];
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=k;i++){
        int x;scanf("%d",&x);v[x]=true;
    }
    for(int i=1;i<=m;i++){
        int u,v;scanf("%d%d",&u,&v);
        s[u]|=1<<v-1;s[v]|=1<<u-1;
    }
    dp[(1<<n)-1]=1;
    for(int i=(1<<n)-1;i>=0;i--){
        for(int j=1;j<=n;j++){
            if(((i>>(j-1))&1)&&(v[j]||(s[j]&(((1<<n)-1)^i))))dp[i^(1<<j-1)]+=dp[i];
        }
        
    }
    cout<<dp[0]<<endl;
    return 0;
}

王五

赛后问了一下切了这题的,一堆解法。几个人写的标算(不知道是标算还是暴力哈希过的),差不多的人数写的 AC 自动机,还有一个写了 SAM+线段树,然后写 SA 的也是就我一个。

首先把所有串拼起来中间加分隔符,后缀排序之后对于每个串就可以在 sa 上二分找到包含这个串的后缀的左右端点。这样就是个区间众数了。我写的分块,赛时忘了还有莫队这种东西。

虽然 4.4k 但是基本都是板子叠起来,挺好写的,一遍就写对了。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
int n,num;
char t[200010];
int s[200010],sa[200010],rk[200010],rk2[200010],key[200010],cnt[200010],bel[200010];
int len[200010],ht[200010],pos[200010],id[200010];
void getsa(){
    int m=5;
    for(int i=1;i<=n;i++){
        rk[i]=s[i];cnt[rk[i]]++;
    }
    for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
    for(int i=n;i>=1;i--)sa[cnt[rk[i]]--]=i;
    for(int w=1;;w<<=1){
        int p=0;
        for(int i=n;i>n-w;i--)id[++p]=i;
        for(int i=1;i<=n;i++){
            if(sa[i]>w)id[++p]=sa[i]-w;
        }
        memset(cnt+1,0,m*4);
        for(int i=1;i<=n;i++){
            key[i]=rk[id[i]];cnt[key[i]]++;
        }
        for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
        for(int i=n;i>=1;i--)sa[cnt[key[i]]--]=id[i];
        memcpy(rk2+1,rk+1,n*4);
        p=0;
        for(int i=1;i<=n;i++){
            rk[sa[i]]=(rk2[sa[i]]==rk2[sa[i-1]]&&rk2[sa[i]+w]==rk2[sa[i-1]+w])?p:++p;
        }
        if(p==n){
            for(int i=1;i<=n;i++)sa[rk[i]]=i;
            break;
        }
        m=p;
    }
}
void getht(){
    for(int i=1,k=0;i<=n;i++){
        if(rk[i]==0)continue;
        if(k)k--;
        while(s[i+k]==s[sa[rk[i]-1]+k])k++;
        ht[rk[i]]=k;
    }
}
struct ST{
    int st[200010][21];
    void build(){
        for(int i=1;i<=n;i++)st[i][0]=ht[i];
        for(int j=1;j<=__lg(n);j++){
            for(int i=1;i+(1<<j)-1<=n;i++){
                st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
            }
        }
    }
    int lcp(int l,int r){
        if(l==r)return n-l+1;
        l++;int k=__lg(r-l+1);
        return min(st[l][k],st[r-(1<<k)+1][k]);
    }
}st;
int getl(int id){
    int l=1,r=pos[id];
    while(l<r){
        int mid=(l+r)>>1;
        if(st.lcp(mid,pos[id])<len[id])l=mid+1;
        else r=mid;
    }
    return l;
}
int getr(int id){
    int l=pos[id],r=n;
    while(l<r){
        int mid=(l+r+1)>>1;
        if(st.lcp(pos[id],mid)<len[id])r=mid-1;
        else l=mid;
    }
    return l;
}
namespace block{
    int sq,blk;
    int L[510],R[510],belong[200010],a[200010];
    int cnt[510][200010],f[510][510];
    void build(){
        for(int i=1;i<=n;i++)a[i]=bel[sa[i]];
        sq=sqrt(n);blk=n/sq;
        for(int i=1;i<=blk;i++){
            L[i]=R[i-1]+1;
            R[i]=L[i]+sq-1;
        }
        R[blk]=n;
        for(int i=1;i<=blk;i++){
            for(int j=L[i];j<=R[i];j++)belong[j]=i;
        }
        for(int i=1;i<=blk;i++){
            for(int j=1;j<=num;j++)cnt[i][j]=cnt[i-1][j];
            for(int j=L[i];j<=R[i];j++)if(a[j])cnt[i][a[j]]++;
        }
        for(int i=1;i<=blk;i++){
            for(int j=1;j<=num;j++)f[i][i]=max(f[i][i],cnt[i][j]-cnt[i-1][j]);
            for(int j=i+1;j<=blk;j++){
                f[i][j]=f[i][j-1];
                for(int k=L[j];k<=R[j];k++)f[i][j]=max(f[i][j],cnt[j][a[k]]-cnt[i-1][a[k]]);
            }
        }
    }
    int tmp[200010];
    int query(int l,int r){
        int ans=0;
        if(belong[l]==belong[r]){
            for(int i=l;i<=r;i++){
                if(a[i])tmp[a[i]]++,ans=max(ans,tmp[a[i]]);
            }
            for(int i=l;i<=r;i++)if(a[i])tmp[a[i]]=0;
            return ans;
        }
        ans=f[belong[l]+1][belong[r]-1];
        for(int i=l;i<=R[belong[l]];i++){
            if(a[i])tmp[a[i]]++,ans=max(ans,cnt[belong[r]-1][a[i]]-cnt[belong[l]][a[i]]+tmp[a[i]]);
        }
        for(int i=L[belong[r]];i<=r;i++){
            if(a[i])tmp[a[i]]++,ans=max(ans,cnt[belong[r]-1][a[i]]-cnt[belong[l]][a[i]]+tmp[a[i]]);
        }
        for(int i=l;i<=R[belong[l]];i++)if(a[i])tmp[a[i]]=0;
        for(int i=L[belong[r]];i<=r;i++)if(a[i])tmp[a[i]]=0;
        return ans;
    }
}
int main(){
    scanf("%d",&num);
    for(int i=1;i<=num;i++){
        scanf("%s",t+1);len[i]=strlen(t+1);
        pos[i]=n+1;
        for(int j=1;j<=len[i];j++){
            if(t[j]=='A')s[++n]=1;
            else if(t[j]=='T')s[++n]=2;
            else if(t[j]=='C')s[++n]=3;
            else s[++n]=4;
            bel[n]=i;
        }
        n++;
    }
    getsa();getht();
    st.build();block::build();
    for(int i=1;i<=num;i++)pos[i]=rk[pos[i]];
    for(int i=1;i<=num;i++){
        int l=getl(i),r=getr(i);
        printf("%d\n",block::query(l,r));
    }
    return 0;
}

赵六

这玩意就是把最短路 DAG 跑出来之后求每个点的支配边个数。那么支配树裸题。

稍微说一下 DAG 上的支配树怎么跑的。按拓扑序求,每次对于点 \(x\) 找到所有能直接到达 \(x\) 的所有节点(就是连边到 \(x\) 的点)在支配树上的 lca 作为 \(x\) 在支配树上的父亲。这是求支配点,支配边就直接把边也当成点一块跑就行了。好像有更高级点的方法。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
int n,m;
struct node{
    int v,w,next;
}edge[1000010];
int t,cnt,head[800010],ind[800010];
void add(int u,int v,int w=0){
    edge[++t].v=v;edge[t].w=w;edge[t].next=head[u];head[u]=t;
}
long long dis[300010];
bool v[300010];
struct stu{
    int x;long long w;
    bool operator<(const stu &s)const{
        return w>s.w;
    }
};
vector<int>pre[300010];

void dijkstra(int st){
    priority_queue<stu>q;
    memset(dis,0x3f,sizeof(dis));
    dis[st]=0;
    q.push({st,0});
    while(!q.empty()){
        int x=q.top().x;q.pop();
        if(!v[x]){
            v[x]=true;
            for(int i=head[x];i;i=edge[i].next){
                if(dis[edge[i].v]>dis[x]+edge[i].w){
                    dis[edge[i].v]=dis[x]+edge[i].w;
                    pre[edge[i].v].clear();
                    pre[edge[i].v].push_back(x);
                    q.push({edge[i].v,dis[edge[i].v]});
                }
                else if(dis[edge[i].v]==dis[x]+edge[i].w){
                    pre[edge[i].v].push_back(x);
                }
            }
        }
    }
    t=0;cnt=n;
    for(int i=1;i<=n;i++)head[i]=0;
    for(int i=1;i<=n;i++){
        for(int f:pre[i]){
            cnt++;add(f,cnt);add(cnt,i);
            ind[cnt]++;ind[i]++;
        }
    }
}
int fa[800010][21],lc[800010],dep[800010],val[800010];
int lca(int x,int y){
    if(dep[x]>dep[y])swap(x,y);
    for(int i=__lg(cnt);i>=0;i--)if(dep[fa[y][i]]>=dep[x])y=fa[y][i];
    if(x==y)return x;
    for(int i=__lg(cnt);i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
void build(){
    queue<int>q;
    q.push(1);
    while(!q.empty()){
        int x=q.front();q.pop();
        dep[x]=dep[lc[x]]+1;fa[x][0]=lc[x];
        for(int i=1;i<=__lg(cnt);i++)fa[x][i]=fa[fa[x][i-1]][i-1];
        val[x]=val[lc[x]];
        if(x>n)val[x]++;
        for(int i=head[x];i;i=edge[i].next){
            ind[edge[i].v]--;
            if(!lc[edge[i].v])lc[edge[i].v]=x;
            else lc[edge[i].v]=lca(lc[edge[i].v],x);
            if(!ind[edge[i].v])q.push(edge[i].v);
        }
    }
}
int read(){
    int x=0;char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return x;
}
int main(){
    n=read();m=read();
    for(int i=1;i<=m;i++){
        int u=read(),v=read(),w=read();
        add(u,v,w);add(v,u,w);
    }
    dijkstra(1);
    build();
    for(int i=1;i<=n;i++)printf("%d\n",val[i]);
    return 0;
}
posted @ 2023-02-16 14:16  gtm1514  阅读(20)  评论(0编辑  收藏  举报