zoukankan      html  css  js  c++  java
  • 2017.8.27 考试

    考场做法:

    把所有的边按编号小的点从大到小排序

    依次加边,并查集维护

    合并时 fa[]强制为编号小的点

    当出现环时,如果fa<=k,ans++

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define N 1000001
    #define M 2000001
    using namespace std;
    int fa[N];
    struct node
    {
        int u,v;
    }e[M];
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    int find(int i) { return fa[i]==i ? fa[i] : fa[i]=find(fa[i]); }
    bool cmp(node p,node q)
    {
        if(p.u!=q.u) return p.u>q.u;
        return p.v>q.v;
    }
    int main()
    {
        freopen("tour.in","r",stdin);
        freopen("tour.out","w",stdout);
        int n,m,k;
        read(n); read(m); read(k);
        for(int i=1;i<=n;i++) fa[i]=i;
        int u,v,r1,r2,tmp1=0,tmp2=0,tot=0;
        for(int i=1;i<=m;i++) 
        {
            read(u); read(v);
            if(u==v) { tmp1++; continue; }
            e[++tot].u=min(u,v);
            e[tot].v=max(u,v);
        }
        m=tot;
        sort(e+1,e+m+1,cmp);
        for(int i=1;i<=m;i++)
        {
            u=e[i].u; v=e[i].v;
            r1=find(u); r2=find(v);
            if(r1!=r2) 
            {
                if(r1<r2) swap(r1,r2);
                fa[r1]=r2;
            }
            else if(fa[r1]<=k) tmp2++;
        }
        printf("%d",tmp1+tmp2);
    }
    View Code

    上面解法中的排序没有必要

    将边分为两类

    1、定点编号都>k

    2、至少有一个点的编号<=k

    先把第一类用并查集合并

    合并第二类时,遇环就ans++

    #include<cstdio>
    #include<iostream>
    #define N 1000001
    #define M 2000001
    using namespace std;
    int fa[N];
    struct node
    {
        int u,v;
    }e[M];
    int find(int i) { return fa[i]==i ? i : fa[i]=find(fa[i]); }
    int read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    int main()
    {
        freopen("tour.in","r",stdin);
        freopen("tour.out","w",stdout);
        int n,m,k;
        read(n); read(m); read(k);
        for(int i=1;i<=n;i++) fa[i]=i;
        int u,v,r1,r2,tot=0;
        for(int i=1;i<=m;i++)
        {
            read(u); read(v);
            if(u>k && v>k)
            {
                r1=find(u);  r2=find(v);
                fa[r1]=r2;
            }
            else
            {
                e[++tot].u=u; e[tot].v=v;
            }
        }
        int ans=0;
        for(int i=1;i<=tot;i++)
        {
            r1=find(e[i].u); r2=find(e[i].v);
            if(r1==r2) ans++;
            fa[r1]=r2;
        }
        printf("%d",ans);
    }
    View Code

    每个数最多开6次就变成1了

    线段树维护区间是否全变成1

    全变成1了就跳过

    注意l可能大于r,被坑了

    #include<cmath>
    #include<cstdio>
    #include<iostream>
    #define N 100001
    using namespace std;
    typedef long long LL;
    LL sum[N<<2],ans;
    int mid[N<<2];
    bool f[N<<2];
    int opl,opr;
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    void read(LL &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    void build(int k,int l,int r)
    {
        if(l==r) 
        { 
            read(sum[k]); 
            if(sum[k]==1) f[k]=true;
            return;
        }
        mid[k]=l+r>>1;
        build(k<<1,l,mid[k]);
        build(k<<1|1,mid[k]+1,r);
        sum[k]=sum[k<<1]+sum[k<<1|1];
        f[k]=f[k<<1]&f[k<<1|1];
    }
    void change(int k,int l,int r)
    {
        if(f[k]) return;
        if(l==r) 
        {
            sum[k]=sqrt(sum[k]);
            if(sum[k]==1) f[k]=true;
            return;
        }
        if(opl<=mid[k]) change(k<<1,l,mid[k]);
        if(opr>mid[k]) change(k<<1|1,mid[k]+1,r);
        sum[k]=sum[k<<1]+sum[k<<1|1];
        f[k]=f[k<<1]&f[k<<1|1];
    }
    void query(int k,int l,int r)
    {
        if(l>=opl && r<=opr) { ans+=sum[k]; return; }
        if(opl<=mid[k]) query(k<<1,l,mid[k]);
        if(opr>mid[k]) query(k<<1|1,mid[k]+1,r);
    }
    void out(LL x)
    {
        if(x/10) out(x/10);
        putchar(x%10+'0');
    }
    int main()
    {
        freopen("sequence.in","r",stdin);
        freopen("sequence.out","w",stdout);
        int n,m,ty; 
        read(n);
        build(1,1,n);
        read(m);
        while(m--)
        {
            read(ty); read(opl); read(opr);
            if(opl>opr) swap(opl,opr);
            if(!ty)  change(1,1,n);
            else ans=0,query(1,1,n),out(ans),printf("
    ");
        }
    }
    View Code

     

    单词i向单词j连一条边,边权为j接到i后面所需的增加的长度

    0向每个单词连边权为单词长度的边

    那么题意转化为在这张图上走m步的最短长度

     单词只有200,出现次数很大

    用倍增加速floyd

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #define N 201
    #define M 100001
    using namespace std;
    typedef unsigned long long LL;
    const int seed=131;
    int n,m;
    string s[N];
    vector<LL>hash[N];
    LL bit[M],h[M]; 
    struct mat
    {
        LL a[N][N];
        void init()
        {
            memset(a,-1,sizeof(a));
        }
        mat operator * (mat b)
        {
            mat res; 
            res.init();
            for(int k=0;k<=n;k++)
                for(int i=0;i<=n;i++)
                    if(a[i][k]!=-1)
                        for(int j=0;j<=n;j++)
                            if(b.a[k][j]!=-1)
                                res.a[i][j]=res.a[i][j]<0 ? a[i][k]+b.a[k][j] : min(res.a[i][j],a[i][k]+b.a[k][j]);
            return res;
        }
    };
    void out(LL x)
    {
        if(x/10) out(x/10);
        putchar(x%10+'0');
    }
    void solve()
    {
        mat x; 
        x.init();
        for(int i=1;i<=n;i++) x.a[0][i]=s[i].length();
        for(int i=1;i<=n;i++)
        {
            int t1=s[i].length(),mx=0;
            LL cur=0;
            for(t1--;t1>=0;--t1)
            {
                cur+=s[i][t1]*bit[mx];
                h[mx++]=cur;
            }
            for(int j=1;j<=n;j++)
            {
                int len=min(s[i].length(),s[j].length()),res=0;
                if(i==j) --len;
                for(int k=0;k<len;k++)
                    if(h[k]==hash[j][k]) res=k+1;
                x.a[i][j]=s[j].length()-res;
            }
        }
        mat res; res=x;
        for(--m;m;m>>=1,x=x*x)
            if(m&1) res=res*x;
        LL ans=1e18;
        for(int i=1;i<=n;i++) ans=min(ans,res.a[0][i]);
        out(ans);
    }
    int main()
    {
        freopen("hamster.in","r",stdin);
        freopen("hamster.out","w",stdout);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            cin>>s[i];
            LL cur=0;
            int len=s[i].length();
            for(int j=0;j<len;j++)
            {
                cur=cur*seed+s[i][j];
                hash[i].push_back(cur);
            }
        }
        bit[0]=1;
        for(int i=1;i<M;i++) bit[i]=bit[i-1]*seed;
        solve();
    }
    View Code

    考场kmp预处理+dfs10分代码:

    #include<ctime>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    char s[201][100001];
    char ss[200001];
    int tim,n,m,minn=1e5+1,cut[201][201],len[201],f[201],ans;
    int kmp(int a,int l)
    {
        int j;
        for(int i=1;i<l;i++)
        {
            j=f[i];
            while(j && ss[i]!=ss[j]) j=f[j];
            f[i+1]= ss[i]==ss[j] ? j+1 : 0;        
        }
        int now=f[l];
        while(now>=a) now=f[now];
        return now;
    }
    void dfs(int now,int last,int length,bool have)
    {
        if(clock()-tim>=2980)
        {
            printf("%d",ans);
            exit(0);
        }
        if(length>=ans) return;
        if(now==m+1) 
        {
            ans=length;
            return;
        }
        for(int i=1;i<=n;i++)
            if(!last || cut[i][last] || have)  
                dfs(now+1,i,length+len[i]-cut[i][last],cut[i][last]);
    }
    int main()
    {
        freopen("hamster.in","r",stdin);
        freopen("hamster.out","w",stdout);
        tim=clock();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s[i]);
            len[i]=strlen(s[i]);
            minn=min(minn,len[i]);
        }
        int l;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                l=0;
                for(int k=0;k<len[i];k++) ss[l++]=s[i][k];
                for(int k=0;k<len[j];k++) ss[l++]=s[j][k];
                cut[i][j]=kmp(len[i],l);
            }    
        ans=minn*m;
        dfs(1,0,0,false);
        printf("%d",ans);
    }
    View Code
  • 相关阅读:
    【PHP】php重写session的存储机制
    【Javascript】原生js 全特效微博发布面板效果实现
    【Javascript】原生js百叶窗效果的实现及原理介绍
    【jQuery】jquery全屏滚动插件【fullPage.js】API 使用方法总结
    从百度音乐和酷狗音乐的分类想到的
    jQuer __Ajax DOM
    面向对象闭包 继承
    Git
    设计模式
    html5标签大全
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7461891.html
Copyright © 2011-2022 走看看