zoukankan      html  css  js  c++  java
  • 2014 ACM/ICPC Asia Regional Xi'an Online

    2014西安网络赛


    A. Post Robot

    把每种单词都kmp跑一遍,顺序输出即可

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <map>
    #include <cstring>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <vector>
    #include <iterator>
    #include <string>
    #include <deque>
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    #define per(i,a,b) for(int i=a;i>=b;--i)
    #define pb push_back
    #define MP make_pair
    #define fr first
    #define sc second
    #define PII pair<int,int>
    #define VI vector<int>
    typedef long long ll;
    typedef unsigned long long ull;
    
    inline int read() {
        char c=getchar();int x=0,f=1;
        while(!isdigit(c)){if(f=='-')f=-1;c=getchar();}
        while(isdigit(c)){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    const int N = 1000500;
    using namespace std;
    
    int n;
    string s,t,s1="Apple",s2="iPhone",s3="iPod",s4="iPad",s5="Sony";
    int nxt[N],vis[N];
    void kmp_pre(string s) {
        int i,j,m=s.size();
        j=nxt[0]=-1;
        i=0;
        while(i<m){
            while(-1!=j&&s[i]!=s[j])j=nxt[j];
            nxt[++i]=++j;
        }
    }
    void kmp(string s,string t,int f) {
        int i,j,n=s.size(),m=t.size();
        i=j=0;
        while(i<n){
            while(-1!=j&&s[i]!=t[j])j=nxt[j];
            ++i;++j;
            if(j>=m) {
                //printf("%d ",i);
                vis[i] = f;
                j=nxt[j];
            }
        }
    }
    int main() {
    //    freopen("in.txt","r",stdin);
    //    freopen("out.txt","w",stdout);
        memset(vis,-1,sizeof(vis));
        int f=0;
        while(getline(cin,t)){
            if(f) s+=" ";f=1;
            s+=t;
        }
    
        kmp_pre(s1); kmp(s,s1,0);
        kmp_pre(s2); kmp(s,s2,0);
        kmp_pre(s3); kmp(s,s3,0);
        kmp_pre(s4); kmp(s,s4,0);
        kmp_pre(s5); kmp(s,s5,1);
        rep(i,1,s.size())
            if(vis[i]==0) puts("MAI MAI MAI!");
            else if(vis[i]==1) puts("SONY DAFA IS GOOD!");
        return 0;
    }
    
    

    B. Boring String Problem

    后缀数组的帮我们排好序了,然后取后缀的前缀即可。严格第k小,就处理一下减去Height[i]即可去重,取前缀和,二分就可以找到严格第k小的串,然后问题就是,求一个串它在整个串中出现的最左边的位置。以当前这个串的左端点为中心,直接在Height数组里二分最左或最右的公共前缀长度恰好大于等于串长的位置,然后在这个区间询问最小的SA值即可。讲道理正解挺好想的。。。(用了两天发现自己的后缀数组板子有错,然后又发现不会二分。。。网上又找了一份大佬板子

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <map>
    #include <cstring>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <vector>
    #include <iterator>
    #include <string>
    #include <deque>
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    #define per(i,a,b) for(int i=a;i>=b;--i)
    #define pb push_back
    #define MP make_pair
    #define fr first
    #define sc second
    #define PII pair<int,int>
    #define VI vector<int>
    typedef long long ll;
    typedef unsigned long long ull;
    const int N = 100005;
    inline int readint() {
        char c=getchar();int x=0,f=1;
        while(!isdigit(c)){if(f=='-')f=-1;c=getchar();}
        while(isdigit(c)){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    using namespace std;
    int n;
    char c[N],str[N];
    int rnk[N] , SA[N] , Height[N];
    int X[N] , Y[N] , sum[N];
    int f[101000][20] , fm[101000][20];
    bool cmp(int *r,int a,int b,int l) {
        return ( r[a] == r[b] && r[a+l] == r[b+l] );
    }
    void calc() {
        int l , p , *x = X , *y = Y , m = 128;
        rep(i,0,m) sum[i] = 0;
        rep(i,1,n) sum[ x[i] = c[i] ] ++;
        rep(i,1,m) sum[i] += sum[i-1];
        per(i,n,1) SA[ sum[ x[i] ]-- ] = i;
        for ( l = 1 , p = 1 ; l <= n ; m = p , l *= 2 ) {
            p = 0;
            rep(i,n-l+1,n) y[++p] = i;
            rep(i,1,n) if ( SA[i] > l ) y[++p] = SA[i] - l;
            rep(i,0,m) sum[i] = 0;
            rep(i,1,n) sum[ x[y[i]] ] ++;
            rep(i,1,m) sum[i] += sum[i-1];
            per(i,n,1) SA[ sum[ x[y[i]] ]-- ] = y[i];
            swap( x , y );
            x[SA[1]] = 1; p = 2;
            rep(i,2,n)
                x[ SA[i] ] = cmp(y,SA[i-1],SA[i],l) ? p - 1 : p++;
        }
        rep(i,1,n) rnk[SA[i]] = i;
        p = 0;
        rep(i,1,n) {
            if ( rnk[i] == 1 ) continue;
            while ( c[i+p] == c[SA[rnk[i]-1]+p] ) p ++;
            Height[rnk[i]] = p;
            if ( p ) p --;
        }
    }
    void init() {
        n = strlen(str);
        for(int i=0;i<n;++i) c[i+1] = str[i];c[n+1]=0;
    }
    int ST_h[N][22], ST_sa[N][22],Log[N];
    void init_rmq() {
        Log[1] = 0;
        rep(i,2,n) Log[i]=Log[i>>1]+1LL;
        rep(i,1,n) ST_h[i][0]=Height[i], ST_sa[i][0]=SA[i];
    
        rep(j,1,20)for(int i=1;i+(1<<j-1)<=n;++i) {
            ST_h[i][j] = min(ST_h[i][j-1],ST_h[i+(1<<(j-1))][j-1]);
            ST_sa[i][j] = min(ST_sa[i][j-1],ST_sa[i+(1<<(j-1))][j-1]);
        }
    }
    int ask_h(int l,int r) {
        if(l==r)return ST_h[l][0];
        if(l>r)swap(l,r);
        ++l;
        int p = Log[r-l+1];
        return min(ST_h[l][p],ST_h[r-(1<<p)+1][p]);
    }
    int ask_sa(int l,int r) {
        if(l>r)swap(l,r);
        int p = Log[r-l+1];
        return min(ST_sa[l][p],ST_sa[r-(1<<p)+1][p]);
    }
    ll s[N];
    
    int fd(int L,int len) {
        int l1=1,r1=L-1,ansl=L;
        while(l1<r1) {
            int mid = (l1+r1)>>1;
            if(ask_h(mid,L)>=len) r1=mid;
            else l1=mid+1;
        }
        if(ask_h(l1,L)>=len)ansl = min(ansl,l1);
        int l2=L+1,r2=n,ansr=L,tmp=-1;
        while(l2<=r2) {
            int mid = (l2+r2)>>1;
            if(ask_h(L,mid)<len) tmp=mid,r2=mid-1;
            else l2=mid+1;
        }
        if(tmp!=-1&&ask_h(L,tmp)<len)--tmp;
        else if(tmp==-1&&ask_h(L,n)>=len) tmp=n;
        if(tmp>=L+1&&tmp<=n&&ask_h(L,r2)>=len)ansr = max(r2,ansr);
        int x = ask_sa(ansl,ansr);
        return x;
    }
    void solve(ll k,int &l,int &r) {
        int p = lower_bound(s+1,s+1+n,k) - s;
        l = SA[p];
        int len = k - s[p-1] + Height[p];
        l = fd(p,len);
        r = l+len-1;
        return;
    }
    int main() {
        while(scanf(" %s",str)!=EOF) {
            init();
            calc();
            init_rmq();
            sum[0]=0;
            rep(i,1,n) s[i] = s[i-1] + (n-SA[i]-Height[i]+1);
            int q=readint();
            int  l=0,r=0;
            while(q--) {ll x;
                scanf("%I64d",&x);
                x = (ll)(l^r^x) + 1LL;
                if(x>(ll)s[n]) {
                    l=r=0;
                    puts("0 0");
                    continue;
                }
                solve(x,l,r);
                printf("%d %d
    ",l,r);
            }
        }
        return 0;
    }
    
    
    

    C. Paint Pearls

    先想暴力dp,(dp[i] = min(dp[j-1]+D(j,i)^2), D(l,r):表示[l,r]区间内不同数的个数)。长得想斜率优化,可是搞不出来。然后,发现只有区间的长度大于区间种类的平方时,才会有贡献,否则不如一个个加起来。于是枚举以i为右端点的区间包含k种数字,显然(k^2)不能大过i,现在就是要求以i为右端点包含k种数字,的最左边的位置,一开始写了主席树,然后二分左端点的两个log做法。tle了之后,发现可以双指针预处理pre[i][j]表示以i为右端点,包含j种元素的最远左端点,因为有个离散化,是一个log。所以预处理复杂度是(O(n sqrt{n} logn)),dp是(O(n sqrt{n}))的,然而还是t了。。。可能这个复杂度还是有点问题。。。还是写搓了??我再努力补。。

    不优化确实会tle,学习了一些优化,换成刷表法dp,最重要优化的是当计算出的dp[i]大于等于dp[n]时break。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <map>
    #include <cstring>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <vector>
    #include <iterator>
    #include <string>
    #include <deque>
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    #define per(i,a,b) for(int i=a;i>=b;--i)
    #define mem(W) memset(W,0,sizeof(W))
    #define pb push_back
    #define MP make_pair
    #define fr first
    #define sc second
    #define PII pair<int,int>
    #define VI vector<int>
    typedef long long ll;
    typedef unsigned long long ull;
    const int N = 50010;
    const ll inf = 1000000000000000LL;
    inline int read() {
        char c=getchar();int x=0,f=1;
        while(!isdigit(c)){if(f=='-')f=-1;c=getchar();}
        while(isdigit(c)){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    using namespace std;
    vector<ll> v;
    int getid(ll x) {
        return lower_bound(v.begin(),v.end(),x) - v.begin() + 1;
    }
    
    int n;
    int a[N],b[N],A[N];
    ll dp[N];
    int vis[N];
    int main() {
        while(scanf("%d",&n)!=EOF) {
            v.clear();
            rep(i,1,n)a[i]=read(),dp[i]=inf,v.pb(a[i]);
            sort(v.begin(),v.end());
            v.erase(unique(v.begin(),v.end()),v.end());
            for(int i=1;i<=n;++i) b[i]=getid(a[i]);
    
            dp[0]=0;
            rep(i,0,n-1) {
                int sz = 0;
                rep(j,i+1,n) {
                    if(!vis[b[j]]) vis[b[j]]=1, A[++sz]=b[j];
                    if(dp[i]+sz*sz>=dp[n]) break;  //***
                    if(sz*sz>n) break;
                    dp[j] = min(dp[j],dp[i]+sz*sz);
                }
                rep(j,1,sz) vis[A[j]]=0;
            }
            printf("%I64d
    ",dp[n]);
        }
        return 0;
    }
    
    

    E. Game

    手推了几组,找规律的。把每一堆的大小都异或起来就星了。

    #include <cstdio>
    #include <algorithm>
    #include <map>
    #include <cstring>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <vector>
    #include <iterator>
    #include <string>
    #include <deque>
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    #define per(i,a,b) for(int i=a;i>=b;--i)
    #define pb push_back
    #define MP make_pair
    #define fr first
    #define sc second
    #define PII pair<int,int>
    #define VI vector<int>
    typedef long long ll;
    typedef unsigned long long ull;
    
    inline int read() {
        char c=getchar();int x=0,f=1;
        while(!isdigit(c)){if(f=='-')f=-1;c=getchar();}
        while(isdigit(c)){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    using namespace std;
    
    int n,x;
    
    int main() {
        while(scanf("%d",&n)!=EOF){
            int ans=0;
            rep(i,1,n){
                int x=read();ans^=x;
            }
            if(!ans)puts("Lose");
            else puts("Win");
        }
        return 0;
    }
    
    

    F. Dice

    直接从123456开始bfs出到每种状态的距离即可。查询时,替换下标即可。

    #include <cstdio>
    #include <algorithm>
    #include <map>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #include <queue>
    #include <set>
    #include <vector>
    #include <iterator>
    #include <string>
    #include <deque>
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    #define per(i,a,b) for(int i=a;i>=b;--i)
    #define pb push_back
    #define MP make_pair
    #define fr first
    #define sc second
    #define PII pair<int,int>
    #define VI vector<int>
    typedef long long ll;
    typedef unsigned long long ull;
    const int N = 654321 + 10;
    inline int read() {
        char c=getchar();int x=0,f=1;
        while(!isdigit(c)){if(f=='-')f=-1;c=getchar();}
        while(isdigit(c)){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    using namespace std;
    int hs(string s) {
        int hs = 0;
        for(int i=0;i<6;++i) hs = hs*10 + (s[i]-'0');
        return hs;
    }
    string t;
    string fhs(int x) {
        t.clear();
        while(x) {
            t += (char)(x%10+'0');
            x/=10;
        }
        reverse(t.begin(),t.end());
        return t;
    }
    string tx,tx2;
    int rt1(int x) {
        tx = fhs(x);
        tx2 = tx;
        tx2[2-1] = tx[3-1];
        tx2[4-1] = tx[2-1];
        tx2[1-1] = tx[4-1];
        tx2[3-1] = tx[1-1];
        return hs(tx2);
    }
    int rt2(int x) {
        tx = fhs(x);
        tx2 = tx;
        tx2[2-1] = tx[4-1];
        tx2[3-1] = tx[2-1];
        tx2[1-1] = tx[3-1];
        tx2[4-1] = tx[1-1];
        return hs(tx2);
    }
    int rt3(int x) {
        tx = fhs(x);
        tx2 = tx;
        tx2[2-1] = tx[5-1];
        tx2[6-1] = tx[2-1];
        tx2[1-1] = tx[6-1];
        tx2[5-1] = tx[1-1];
        return hs(tx2);
    }
    int rt4(int x) {
        tx = fhs(x);
        tx2 = tx;
        tx2[2-1] = tx[6-1];
        tx2[5-1] = tx[2-1];
        tx2[1-1] = tx[5-1];
        tx2[6-1] = tx[1-1];
        return hs(tx2);
    }
    int dis[N],vis[N];
    void bfs(string s) {
        memset(dis,-1,sizeof(dis));
        memset(vis,0,sizeof(vis));
        int u = hs(s);
        dis[u] = 0;
        queue<int> q;
        q.push(u);
        vis[u]=1;
        while(!q.empty()) {
            int u = q.front(); q.pop();
            int tu = u;
            tu = rt1(u);
            if(!vis[tu]) {
                vis[tu] = 1;
                q.push(tu);
                dis[tu] = dis[u] + 1;
            }
            tu = rt2(u);
            if(!vis[tu]) {
                vis[tu] = 1;
                q.push(tu);
                dis[tu] = dis[u] + 1;
            }
            tu = rt3(u);
            if(!vis[tu]) {
                vis[tu] = 1;
                q.push(tu);
                dis[tu] = dis[u] + 1;
            }
            tu = rt4(u);
            if(!vis[tu]) {
                vis[tu] = 1;
                q.push(tu);
                dis[tu] = dis[u] + 1;
            }
        }
    }
    
    int n,a[10],b[10];
    map<int,int> c;
    int main() {
        string s = "123456";
        bfs(s);
        while(scanf("%d%d%d%d%d%d",&a[1],&a[2],&a[3],&a[4],&a[5],&a[6])!=EOF) {
            scanf("%d%d%d%d%d%d",&b[1],&b[2],&b[3],&b[4],&b[5],&b[6]);
            c.clear();
            rep(i,1,6) c[a[i]] = i;
            int hs = 0;
            rep(i,1,6)hs=hs*10+c[b[i]];
            printf("%d
    ",dis[hs]);
        }
        return 0;
    }
    
    

    H. Number Sequence

    一开始想起一道题,觉得要从高位到低位分治贪心。然后发现过的人有点多啊。就开始找规律。。。于是顺利浪费了大量时间。。。首先发现最大值就是(n*(n+1)) ,而每一个值都可以用一些(2^i-1)组合成,于是我们从大到小贪心的把每个数都异或成(2^i-1)中的尽可能大的值即可

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <map>
    #include <cstring>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <vector>
    #include <iterator>
    #include <string>
    #include <deque>
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    #define per(i,a,b) for(int i=a;i>=b;--i)
    #define pb push_back
    #define MP make_pair
    #define fr first
    #define sc second
    #define PII pair<int,int>
    #define VI vector<int>
    typedef long long ll;
    typedef unsigned long long ull;
    const int N = 1e6 +100000;
    inline int read() {
        char c=getchar();int x=0,f=1;
        while(!isdigit(c)){if(f=='-')f=-1;c=getchar();}
        while(isdigit(c)){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    using namespace std;
    ll n;
    ll a[N],b[N];
    int vis[N];
    void solve() {
        memset(vis,0,sizeof(vis));
        for(int i=n;i>=0;--i) {
            int e = 0;
            for(ll j=20;j>=0;--j) {
                e=(1<<j)-1;
                if(!vis[(e^i)]&&(e^i)<=n) {
                    vis[(e^i)]=1;
                    b[i] = (e^i);
                    break;
                }
            }
        }
    }
    int main() {
        while(scanf("%lld",&n)!=EOF){
            rep(i,0,n)a[i]=read();
            solve();int f=0;
            printf("%lld
    ",(n+1ll)*n);
            rep(i,0,n) {
                if(f)printf(" ");f=1;
                printf("%lld",b[a[i]]);
            }puts("");
        }
        return 0;
    }
    
    

    I. 233 Matrix

    发现n非常小,m很大,于是想到矩阵快速幂,推一下就ok了

    #include <cstdio>
    #include <algorithm>
    #include <map>
    #include <cstring>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <vector>
    #include <iterator>
    #include <string>
    #include <deque>
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    #define per(i,a,b) for(int i=a;i>=b;--i)
    #define pb push_back
    #define MP make_pair
    #define fr first
    #define sc second
    #define PII pair<int,int>
    #define VI vector<int>
    #define rg register
    typedef long long ll;
    typedef unsigned long long ull;
    const ll mod = 10000007;
    inline int read() {
        char c=getchar();int x=0,f=1;
        while(!isdigit(c)){if(f=='-')f=-1;c=getchar();}
        while(isdigit(c)){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    using namespace std;
    ll ans[20][20],c[20][20],d[20][20];
    inline void mul(ll a[][20], ll b[][20], int n){
        for(rg int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)ans[i][j]=0,c[i][j]=a[i][j],d[i][j]=b[i][j];
        for(rg int i=1;i<=n;++i)
        for(rg int k=1;k<=n;++k)if(c[i][k])
        for(rg int j=1;j<=n;++j)if(d[k][j]){
            ans[i][j] = (ans[i][j] + (c[i][k]*d[k][j]))%mod;
        }
        for(rg int i=1;i<=n;++i)
            for(rg int j=1;j<=n;++j)a[i][j]=ans[i][j];
    }
    ll E[20][20],A[20][20];
    inline void mx_pow(ll A[][20],ll b,int n) {
         while(b) {
            if(b&1) mul(E,A,n);
            mul(A,A,n);
            b>>=1LL;
         }
    }
    
    int n;
    ll m,a[20];
    int main() {
        while(scanf("%d%lld",&n,&m)!=EOF) {
            memset(A,0,sizeof(A));
            memset(E,0,sizeof(E));
            rep(i,1,n) a[i] = read();
            a[n+1] = 233; a[n+2] = 1;
            rep(i,1,n+2)E[i][i] = 1;
            rep(i,1,n)rep(j,1,i) A[i][j] = 1;
            rep(i,1,n)A[i][n+1]=1;
            A[n+1][n+1] = 10; A[n+1][n+2] = 3;
            A[n+2][n+2]=1;
    
            mx_pow(A,m,n+2);
    
            ll res = 0;
            rep(i,1,n+2) res = (res + (E[n][i]*a[i])%mod)%mod;
            printf("%lld
    ",res);
        }
        return 0;
    }
    
    
  • 相关阅读:
    【转载】C/C++中extern关键字详解
    【转载】extern "C"的用法解析(原博主就是抄百度百科的,不如另外一篇好)
    lua Date和Time
    MySQL-Linux安装
    Hive-0.13安装
    MR案例:单表关联查询
    MR案例:小文件处理方案
    MR案例:链式ChainMapper
    MR案例:定制Partitioner
    MR案例:多文件输出MultipleOutputs
  • 原文地址:https://www.cnblogs.com/RRRR-wys/p/9347399.html
Copyright © 2011-2022 走看看