zoukankan      html  css  js  c++  java
  • 2017-2018 ACM-ICPC, Asia Daejeon Regional Contest

    题目传送门

    只打了三个小时。

    A. Broadcast Stations

    B. Connect3

    补题:zz

    题解:因为格子是4*4的,而且每次落子的位置最多是只有四个,再加上剪枝,情况不会很多,直接爆搜就行了,再用三进制记录已经合法的情况,去掉重复的情况就行了。(用vs2017交会ac,但c++17会wa1,很奇怪)

    //#pragma comment(linker, "/STACK:102400000,102400000")
    #include<iostream>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<string>
    #include<math.h>
    #include<cmath>
    #include<time.h>
    #include<map>
    #include<set>
    #include<vector>
    #include<queue>
    #include<algorithm>
    #include<numeric>
    #include<stack>
    #include<bitset>
    #include<unordered_map>
    const int maxn = 0x3f3f3f3f;
    const double EI = 2.71828182845904523536028747135266249775724709369995957496696762772407663035354594571382178525166427;
    const double PI = 3.141592653589793238462643383279;
    //#ifdef TRUETRUE
    //#define gets gets_s
    //#endif
    using namespace std;
    int a, b;
    int ans;
    map<int, int>mp;
    bool Judge(int c[10][10], int aa, int bb, int pos)
    {
        if (aa == a && bb == b && pos == 1)
        {
            return false;
        }
        int cc[10][10], i, j;
        for (i = 1; i <= 4; i++)
        {
            for (j = 1; j <= 4; j++)
            {
                cc[i + 1][j + 1] = c[i][j];
            }
        }
        aa++;
        bb++;
        bool flag = false;
        if (cc[aa][bb] == cc[aa - 1][bb] && cc[aa][bb] == cc[aa - 2][bb]
            || cc[aa][bb] == cc[aa + 1][bb] && cc[aa][bb] == cc[aa + 2][bb]
            || cc[aa][bb] == cc[aa][bb - 1] && cc[aa][bb] == cc[aa][bb - 2]
            || cc[aa][bb] == cc[aa][bb + 1] && cc[aa][bb] == cc[aa][bb + 2]
            || cc[aa][bb] == cc[aa + 1][bb + 1] && cc[aa][bb] == cc[aa + 2][bb + 2]
            || cc[aa][bb] == cc[aa - 1][bb - 1] && cc[aa][bb] == cc[aa - 2][bb - 2]
            || cc[aa][bb] == cc[aa - 1][bb] && cc[aa][bb] == cc[aa + 1][bb]
            || cc[aa][bb] == cc[aa][bb - 1] && cc[aa][bb] == cc[aa][bb + 1]
            || cc[aa][bb] == cc[aa - 1][bb - 1] && cc[aa][bb] == cc[aa + 1][bb + 1]
            || cc[aa][bb] == cc[aa - 1][bb + 1] && cc[aa][bb] == cc[aa - 2][bb + 2]
            || cc[aa][bb] == cc[aa + 1][bb - 1] && cc[aa][bb] == cc[aa + 2][bb - 2]
            || cc[aa][bb] == cc[aa - 1][bb + 1] && cc[aa][bb] == cc[aa + 1][bb - 1])
        {
            flag = true;
        }
        if (flag && pos == 2 && aa - 1 == a && bb - 1 == b)
        {
            int tmp = 0;
            for (i = 1;i <= 4;i++)
            {
                for (j = 1;j <= 4;j++)
                {
                    tmp *= 3;
                    tmp += c[i][j];
                }
            }
            if (!mp[tmp])
            {
                ans++;
                mp[tmp] = 1;
            }
            return false;
        }
        if (flag || (!flag && aa - 1 == a && bb - 1 == b))
        {
            return false;
        }
        else
        {
            return true;
        }
    }
    void f(int c[10][10], int d[10], int pos)
    {
        int i;
        for (i = 1; i <= 4; i++)
        {
            if (d[i] <= 4)
            {
                c[d[i]][i] = pos;
                int dd[10][10];
                for (int ii = 1;ii <= 4;ii++)
                {
                    memcpy(dd[ii], c[ii], sizeof(c[ii]));
                }
                if (Judge(dd, d[i], i, pos))
                {
                    d[i]++;
                    f(dd, d, 3 - pos);
                    d[i]--;
                }
                c[d[i]][i] = 0;
            }
        }
    }
    void init(void)
    {
        mp.clear();
    }
    int main(void)
    {
        //ios::sync_with_stdio(false);
        int x;
        while (~scanf("%d %d %d", &x, &a, &b))
        {
            init();
            int c[10][10];
            int d[10] = { 1,1,1,1,1,1,1,1,1,1 };
            d[x]++;
            memset(c, 0, sizeof(c));
            c[1][x] = 1;
            ans = 0;
            f(c, d, 2);
            printf("%d
    ", ans);
        }
        return 0;
    }
    View Code

    C. Game Map

     题意:给定一张无向图,要求找出一个最长的序列,使得这个序列的度数是严格递增的。

    思路:对于每一个点来说,这个点在序列中的位置可以是1,也可以是从和它相邻的且读书小于它的点转移过来的,所以枚举度数从小到大的点即可。

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    const int maxn=100100;
    vector<int>ve[100010];
    unordered_map<int,int>mp[100010];
    int c[100010],de[100010];
    struct s
    {
        int de,id;
    }z[100010];
    inline bool comp(s a,s b)
    {
        return a.de <b.de;
    }
    int main(){
        int n,m,i,z1,z2,si,j,ans;
        while(~scanf("%d %d",&n,&m))
        {
            for(i = 0;i <= n;i++)
            {
                ve[i].clear();
                mp[i].clear();
                c[i] = 1;
                z[i].de = 0;
                z[i].id = i;
                de[i] = 0;
            }
            for(i = 0;i < m;i++)
            {
                scanf("%d %d",&z1,&z2);
                if(z1 > z2)
                {
                    int r = z1;
                    z1 = z2;
                    z2 = r;
                }
                if(z1 != z2 && !mp[z1][z2])
                {
                    mp[z1][z2] = 1;
                    ve[z1].push_back(z2);
                    ve[z2].push_back(z1);
                    z[z1].de++;
                    z[z2].de++;
                    de[z1]++;
                    de[z2]++;
                }
            }
            sort(z,z + n,comp);
            ans = 1;
            for(i = 0;i < n;i++)
            {
                si = ve[z[i].id].size();
                //printf(" %d %d
    ",z[i].id,z[i].de);
                for(j = 0;j < si;j++)
                {
                    //printf("   %d %d %d
    ",z[i].de,z[ve[z[i].id][j]].de,ve[z[i].id][j]);
                    if(z[i].de > de[ve[z[i].id][j]])
                    {
                        c[z[i].id] = max(c[z[i].id],c[ve[z[i].id][j]] + 1);
                    }
                }
                //printf("          %d
    ",c[z[i].id]);
                ans = max(ans,c[z[i].id]);
            }
            printf("%d
    ",ans);
        }
    }
    View Code

    D. Happy Number

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<cstdio>
    #include<algorithm>
    #include<string>
    #include<map>
    #include<queue>
    #include<vector>
    #include<stack>
    #define ll long long
    #define maxn 4001000
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    int n,len;
    map<int,int> mp;
    ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void init()
    {
        scanf("%d",&n); 
        len=1;
        mp[n]=1;
    }
    void work()
    {
        while(1)
        {
            int x=n,ans=0;
            while(x>0)
            {
                ans+=(x%10)*(x%10);
                x/=10; 
            }
            if(ans==1) 
            {
                printf("HAPPY");
                return;
            }
            if(mp[ans]!=0) 
            {
                printf("UNHAPPY");
                return;
            }
            else mp[ans]=++len;
            n=ans;
        }
    }
    int main()
    {
        init();
        work();
    }
    View Code

    E. How Many to Be Happy

    补题:kk

      一开始想了个假算法,没被队友hack,然后wa3?最近好像经常写假算法

      对于这样最小生成树的题的选边问题,我们一定要考虑克鲁斯卡尔的过程,对于一条边权为$w$的边,如果他要在最小生成树上,那么前提条件是权值比他小的边不会把u到v所属的两个结合连接在一起,也就是说,现在我们要去掉一些权值小于$w$的边,让u和v分在不同的两个集合里面,想到这里就会想到最小割的模型,对于每条边,都把权值小于他的边加入到图里,然后求一个最小割就可以了。

      所以,最小生成树的题一定要考虑克鲁斯卡尔!这真是一个神奇的算法,还有对数据范围要敏感,$n=100$也应该想到网络流。

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    
    const ll INFLL = 0x3f3f3f3f3f3f3f3f;
    const int INF = 0x3f3f3f3f;
    const int maxn = 510;
    
    struct Edge {
        int to, flow, nxt;
        Edge(){}
        Edge(int to, int nxt, int flow):to(to),nxt(nxt), flow(flow){}
    }edge[maxn << 2];
    
    int head[maxn], dep[maxn];
    int S, T;
    int N, n, m, tot,ans;
    
    void Init(int n)
    {
        N = n;
        for (int i = 0; i < N; ++i) head[i] = -1;
        tot = 0;
    }
    
    void addv(int u, int v, int w, int rw = 0)
    {
        edge[tot] = Edge(v, head[u], w); head[u] = tot++;
        edge[tot] = Edge(u, head[v], rw); head[v] = tot++;
    }
    
    bool BFS()
    {
        for (int i = 0; i < N; ++i) dep[i] = -1;
        queue<int>q;
        q.push(S);
        dep[S] = 1;
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            for (int i = head[u]; ~i; i = edge[i].nxt)
            {
                if (edge[i].flow && dep[edge[i].to] == -1)
                {
                    dep[edge[i].to] = dep[u] + 1;
                    q.push(edge[i].to);
                }
            }
        }
        return dep[T] < 0 ? 0 : 1;
    }
    
    int DFS(int u, int f)
    {
        if (u == T || f == 0) return f;
        int w, used = 0;
        for (int i = head[u]; ~i; i = edge[i].nxt)
        {
            if (edge[i].flow && dep[edge[i].to] == dep[u] + 1)
            {
                w = DFS(edge[i].to, min(f - used, edge[i].flow));
                edge[i].flow -= w;
                edge[i ^ 1].flow += w;
                used += w;
                if (used == f) return f;
            }
        }
        if (!used) dep[u] = -1;
        return used;
    }
    
    int Dicnic()
    {
        int ans = 0;
        while (BFS())
        {
            ans += DFS(S, INF);
        }
        return ans;
    }
    struct node{
        int u,v,w;
        friend bool operator<(const node &a,const node &b)
        {
            return a.w<b.w;
        }
    }a[maxn];
    int main(){
        while(cin>>n>>m)
        {
            for(int i=1;i<=m;i++)
            {
                scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
            }
            ans=0;
            sort(a+1,a+1+m);
            for(int i=1;i<=m;i++)
            {
                Init(n+1);
                for(int j=1;j<i;j++)
                {
                    if(a[j].w>=a[i].w)break;
                    addv(a[j].u,a[j].v,1);
                    addv(a[j].v,a[j].u,1);
                }
                S=a[i].u,T=a[i].v;
                ans+=Dicnic();
        //        printf("debug
    ");
            }
            printf("%d
    ",ans);
        }
    }
    View Code

    F. Philosphoer's Walk

     题意:给定一张题目里描述的规模的图,输出走k布后的点。

    思路:每一张图都能分解为四张规模一样的图,判断最终会在哪一张小图里和起止点的位置,之后再重复这个操作,直到2*2的图为止。

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    const int maxn=510;
    struct s
    {
        int a,b;
    }in;
    int Pow[110];
    int Node[5][2] = {0,0,1,1,1,2,2,2,2,1};
    inline void init(void)
    {
        int i,tmp = 1;
        for(i = 0;i <= 30;i++)
        {
            Pow[i] = tmp;
            tmp <<= 1;
        }
    }
    inline s f(int num,int step)
    {
        int pos,st;
        s jk;
        if(num == 1)
        {
            s tmp;
            tmp.a = Node[step][0];
            tmp.b = Node[step][1];
            return tmp;
        }
        pos = (step - 1) / (Pow[num - 1] * Pow[num - 1]);
        st = (step - 1) % (Pow[num - 1] * Pow[num - 1]) + 1;
        s nex = f(num - 1,st);
        if(pos == 0)
        {
            jk.a = 0 + nex.b;
            jk.b = 0 + nex.a;
        }
        else if(pos == 1)
        {
            jk.a = 0 + nex.a;
            jk.b = Pow[num - 1] + nex.b;
        }
        else if(pos == 2)
        {
            jk.a = Pow[num - 1] + nex.a;
            jk.b = Pow[num - 1] + nex.b;
        }
        else
        {
            jk.a = Pow[num] + 1 - nex.b;
            jk.b = Pow[num - 1] + 1 - nex.a;
        }
        return jk;
    }
    int main(){
        int n,m,i;
        init();
        while(~scanf("%d %d",&n,&m))
        {
            for(i = 1;i <= 30;i++)
            {
                if(Pow[i] == n)
                {
                    break;
                }
            }
            in = f(i,m);
            printf("%d %d
    ",in.a,in.b);
        }
    }
    View Code

    G. Rectilinear Regions

    H. Rock Paper Scissors

     题解:FFT,把s1串中石头剪刀布的位置记录下来,再把S2串中石头剪刀布的位置记录下来。分输赢做三次FFT。

    #include <cmath>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define maxn (1<<18)
    #define pi 3.141592653589793238462643383
    using namespace std;
    
    struct complex
    {
        double re,im;
        complex(double r=0.0,double i=0.0) {re=r,im=i;}
        void print() {printf("%.lf ",re);}
    } a[maxn*2],b[maxn*2],W[2][maxn*2];
    
    int N,na,nb,rev[maxn*2],n,m;
    char s1[101010],s2[101010];
    double c[maxn*2],ans;
    complex operator +(const complex&A,const complex&B) {return complex(A.re+B.re,A.im+B.im);}
    complex operator -(const complex&A,const complex&B) {return complex(A.re-B.re,A.im-B.im);}
    complex operator *(const complex&A,const complex&B) {return complex(A.re*B.re-A.im*B.im,A.re*B.im+A.im*B.re);}
    
    void FFT(complex*a,int f)
    {
        complex x,y;
        for (int i=0; i<N; i++) if (i<rev[i]) swap(a[i],a[rev[i]]);
        for (int i=1; i<N; i<<=1)
            for (int j=0,t=N/(i<<1); j<N; j+=i<<1)
                for (int k=0,l=0; k<i; k++,l+=t) x=W[f][l]*a[j+k+i],y=a[j+k],a[j+k]=y+x,a[j+k+i]=y-x;
        if (f) for (int i=0; i<N; i++) a[i].re/=N;
    }
    
    void work()
    {
        for (int i=0; i<N; i++)
        {
            int x=i,y=0;
            for (int k=1; k<N; x>>=1,k<<=1) (y<<=1)|=x&1;
            rev[i]=y;
        }
        for (int i=0; i<N; i++) W[0][i]=W[1][i]=complex(cos(2*pi*i/N),sin(2*pi*i/N)),W[1][i].im=-W[0][i].im;
    }
    void doit()
    {
        work(),FFT(a,0),FFT(b,0);
        for (int i=0; i<N; i++) a[i]=a[i]*b[i];
        FFT(a,1);
        for (int i=0; i<na+nb-1; i++) 
        {
            c[i]+=a[i].re;
            if(i>=m-1) ans=max(ans,c[i]);
            //printf("%d %d
    ",i,c[i]);
        }
    }
    
    void popo()
    {   
        scanf("%d%d",&n,&m);
        scanf("%s",s1);
        scanf("%s",s2);
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        na=n;nb=m;
        for(int i=0;i<n;i++)    
            if(s1[i]=='R') a[i].re=1;
        for(int i=0;i<m;i++)
            if(s2[i]=='P') b[m-i-1].re=1;
        for (N=1; N<na||N<nb; N<<=1); N<<=1;
        doit();
        //printf("------
    ");
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        for(int i=0;i<n;i++)    
            if(s1[i]=='P') a[i].re=1;
        for(int i=0;i<m;i++)
            if(s2[i]=='S') b[m-i-1].re=1;
        for (N=1; N<na||N<nb; N<<=1); N<<=1;
        doit();
        //printf("------
    ");
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        for(int i=0;i<n;i++)    
            if(s1[i]=='S') a[i].re=1;
        for(int i=0;i<m;i++)
            if(s2[i]=='R') b[m-i-1].re=1;
        for (N=1; N<na||N<nb; N<<=1); N<<=1;
        doit();
    }
    
    
    int main()
    {
        popo();
        printf("%.lf
    ",ans);
    }
    View Code

    I. Slot Machines

    补题kk

      我们把这个数组倒过来,现在变成了我们要去掉末尾的一段,使得前面部分循环,并且不完整的循环节在数列的前方。对于两段循环来说,开头一部分肯定是一样的(否则怎么能叫循环呢),如果有一段循环不完整,那么开头一部分肯定是一样的,而这里循环的开头就是倒过来的数组的前缀,后面是一个完整的数组,前缀和后缀相同,我们想到了什么呢?kmp!

      但是这里我们只需要$fail$就可以了。

      先对倒过来的数组$fail$一遍,得到$f$数组,然后循环长度就变成了$i-f[i]$,对此我们稍微证明一下为什么。

      对于$i-f[i]>=f[i]$,也就是相等的前缀和后缀不重叠,那么这必然是一个循环长度。

      对于$i-f[i]<f[i]$,也就是相等的前缀喝后缀是重叠的,那么我们就要稍微理解一下,设$len=i-f[i]$那么必然有$s{f[i]->f[i]+len]}==s{f[i]-len->f[i]}$,然后一步一步的画过来,这个也是循环节(这部分还是画图好理解些)

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    const int maxn=1000010;
    int n;
    int a[maxn],f[maxn];
    void fail(){
        f[0]=-1;
        for(int j=1;j<n;j++)
        {
            for(int i=f[j-1];;i=f[i])
            {
                if(a[j]==a[i+1]){
                    f[j]=i+1;
                    break;
                }else if(i==-1)
                {
                    f[j]=-1;
                    break;
                }
            }
        }
    }
    int main(){
        while(cin>>n)
        {
            for(int i=n-1;i>=0;i--)
            {
                scanf("%d",&a[i]);
            }
            fail();
            int k=n,p=1;
            for(int i=0;i<n;i++)
            {
                int kk=n-i-1;
                int pp=i-f[i];
                if(kk+pp<k+p){
                    k=kk,p=pp;
                }else if(kk+pp==k+p&&pp<p){
                    k=kk,p=pp;
                }
            }
            printf("%d %d
    ",k,p);
            
        }
    }
    View Code

    J. Strongly Matchable

    K. Untangling Chain

    L. Vacation Plans

  • 相关阅读:
    MVAPICH
    sql server触发器的例子
    Sql Server 判断表或数据库是否存在
    JS验证用户真实姓名
    js实现瀑布流的一种简单方法实例分享
    C#实现登录窗口(不用隐藏)
    判断滚动条到底部的JS代码
    php 中文字符串首字母的获取函数
    C#获取当前页面的URL
    C#动态生成图书信息XML文件
  • 原文地址:https://www.cnblogs.com/mountaink/p/10503451.html
Copyright © 2011-2022 走看看