• 2016-2017 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2016)


    Time:2018.4.3   18:00 - 22:00

    Link


    A Artwork       solved by ym    solved by czh

    题意

    给一个n×m一个网格,有q个询问,每次询问有两个点坐标,表示从第一个点到第二个点都被标记(这两个点x/ y相同),对于q个询问,每次输出网格共被分成几个区域(1<=n,m<=1e3,q<=10000)

    分析

    比赛的时候对于每个q直接bfs不出意外的tle的起不来,没有好的思路,死掉

    赛后:联通块应该想到并查集来解决

               对询问倒着作,并查集维护联通块即可

               hash函数写反错了一年才找出来  by ym

               赛后学长指点了一下,但写出来后超时,原来是并查集路径压缩错了,以前用的路径压缩都不是很快 by czh

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn = 1000+7;
    const int maxm = 1e6+200;
    int dx[5]={1,-1,0,0};
    int dy[5]={0,0,-1,1};
    
    int n,m,q;
    int num[maxn][maxn];
    int answer[maxm];
    int fa[maxm];
    int x1[maxn*10], y1[maxn*10], x2[maxn*10], y2[maxn*10];
    
    void init()
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                fa[(i-1)*m+j]=(i-1)*m+j;
            }
        }
    }
    
    int findfa(int x)
    {
        if(x==fa[x])
        return x;
        else
        return  fa[x]=findfa(fa[x]);
    }
    int tot=0;
    void join(int x,int y)
    {
        int xx=findfa(x);
        int yy=findfa(y);
        if(xx!=yy)
        {
            fa[yy]=xx;
            tot--;
        }
    }
    
    
    void ok(int x,int y)
    {
        for(int i=0;i<4;i++)
        {
            int xx=x+dx[i];
            int yy=y+dy[i];
            if(xx>=1 && xx<=n && yy>=1 && yy<=m && num[xx][yy]==0)
            {
                join((xx-1)*(m)+yy, (x-1)*m+y);
            }
        }
    }
    
    int main()
    {
        scanf("%d%d%d", &n, &m, &q);
        init();
        for(int i=1;i<=q;i++)
        {
            scanf("%d%d%d%d", &x1[i], &y1[i], &x2[i], &y2[i]);
            if(x1[i]==x2[i])
            {
                for(int j=y1[i];j<=y2[i];j++)
                {
                    num[x1[i]][j]++;
                }
            }
            else
            {
                for(int j=x1[i];j<=x2[i];j++)
                {
                    num[j][y1[i]]++;
                }
            }
        }
        
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(num[i][j]==0)
                {
                    ok(i,j);
                    tot++;
                }
            }
        }
    
        for(int i=q;i>=1;i--)
        {
            answer[i]=tot;
            if(x1[i]==x2[i])
            {
                for(int j=y1[i];j<=y2[i];j++)
                    {
                    --num[x1[i]][j];
                    if(num[x1[i]][j]==0)
                    {
                        tot++;
                        ok(x1[i],j);
                    }
                }
            }
            else
            {
                for(int j=x1[i];j<=x2[i];j++)
                {
                    --num[j][y1[i]];
                    if(num[j][y1[i]]==0)
                    {
                        tot++;
                        ok(j,y1[i]);
                    }
                }
            }
        }
        for(int i=1;i<=q;i++) printf("%d
    ", answer[i]);
        return 0;
    }

    B  Bless You Autocorrect!        solved by none

    题意

    给一本有n个单词的词库具有自动补全功能,优先级从高到低,q个询问,问每个询问的单词的最小输入(1<=n<=1e5,1<=q<=1e5)

    注意:不存在一个单词由多个单词共同构成

    分析

    将所有单词构成一颗字典树,根据优先级建好边后,在树上跑个tree dp

    目前码不出来,留坑

    zls代码

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long LL;
    
    struct Node
    {
        int nxt[26];
        int jump;
        int fa;
    };
    
    Node trie[2000005];
    int n,m;
    string s[100005];
    int en[100005];
    int dist[2000005];
    queue<int> q;
    int num=0;
    
    int insert(string s)
    {
        int now=0,dq;
        for (int i=0;i<s.size();++i)
        {
            int dq=s[i]-'a';
            if (trie[now].nxt[dq]==-1)
            {
                ++num;trie[now].nxt[dq]=num;
                trie[num].fa=now;
                for (int j=0;j<26;++j) trie[num].nxt[j]=-1;
                trie[num].jump=-1;
                add(now,num,1);
                add(num,now,1);
            }
            now=trie[now].nxt[dq];
        }
        return now;
    }
    void addedge(string s,int en)
    {
        int now=0,dq;
        for (int i=0;i<s.size();++i)
        {
            int dq=s[i]-'a';
            if (trie[now].jump==-1)
            {
                add(now,en,1);
                trie[now].jump=en;
            }
            now=trie[now].nxt[dq];
        }
        if (trie[now].jump==-1)
        {
            trie[now].jump=en;        
            add(now,en,1);
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;++i) cin>>s[i];
        for (int i=0;i<26;++i) trie[0].nxt[i]=-1;
        trie[0].jump=0,trie[0].fa=-1;
        for (int i=1;i<=n;++i)
        {
            int tmp=insert(s[i]);
            addedge(s[i],tmp);
        }
        for (int i=1;i<=m;++i)
        {
            cin>>s[0];
            en[i]=insert(s[0]);
        }
        for (int i=0;i<=num;++i) dist[i]=1e9;
        dist[0]=0;
        while (!q.empty()) q.pop();
        q.push(0);
        trie[0].jump=-1;
        while (!q.empty())
        {
            int x=q.front();q.pop();
            for (int i=0;i<26;++i) if (trie[x].nxt[i]!=-1)
            {
                int y=trie[x].nxt[i];
                if (dist[y]!=1e9) continue;
                dist[y]=dist[x]+1;
                q.push(y);
            }
            if (trie[x].fa!=-1)
            {
                int y=trie[x].fa;
                if (dist[y]==1e9){
                dist[y]=dist[x]+1;
                q.push(y);}
            }
            if (trie[x].jump!=-1)
            {
                int y=trie[x].jump;
    
                if (dist[y]==1e9) {
                dist[y]=dist[x]+1;
                q.push(y);}
            }
        }
        for (int i=1;i<=m;++i) printf("%d
    ",dist[en[i]]);
        return 0;
    }

    C Card Hand Sorting         solved by czh

    题意

    有n张牌排成一行,每张牌两个属性,第一个数字/字母代表它在这一类的rank,后一个字母代表它的种类,共有13个rank和4种牌,现要求同种牌必须放在相邻位置,每种牌内部是有序的,问最少需要移动几次(移动是任意的)(n<=52)

    分析

    ym:暴力枚举+maskdp,待补

    czh:注意到n最大为52,枚举花色的顺序和花色内的顺序,然后求最大子序列

    #include<bits/stdc++.h>
    using namespace std;
    
    map<char,int>mp;
    char color[60],a[3];
    int pe[4]={1,2,3,4},ind[60],n,num[60];
    map<char,int>ma;
    int dp[60];
    
    int LIS()
    {
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
            dp[i]=1;
        int maxx=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<i;j++)
            {
                if(num[i]>num[j])
                    dp[i]=max(dp[i],dp[j]+1);
            }
            maxx=max(maxx,dp[i]);
        }
        return maxx;
    }
    
    int main()
    {
        ma['s']=0;ma['h']=1;ma['d']=2;ma['c']=3;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            scanf("%s",a);
            if(a[0]>='0'&&a[0]<='9')
                ind[i]=a[0]-'0';
            else if(a[0]=='T')ind[i]=10;
            else if(a[0]=='J')ind[i]=11;
            else if(a[0]=='Q')ind[i]=12;
            else if(a[0]=='K')ind[i]=13;
            else if(a[0]=='A')ind[i]=14;
            color[i]=a[1];
        }
        int ans=0;
        do{
            for(int i=0;i<16;i++)
            {
                for(int j=1;j<=n;j++)
                {
                    num[j]=pe[ma[color[j]]]*1000;
                    if(((1<<ma[color[j]])&i)==0)
                        num[j]-=ind[j];
                    else
                        num[j]+=ind[j];
                }
                ans=max(ans,LIS());
            }
        }while(next_permutation(pe,pe+4));
        cout<<n-ans<<endl;
    } 

    D Daydreaming Stockbroker    solved by ym   solved by czh

    题意

    给你n天的物价,初始有100元,库存量最大不能超过1e5,问最后做多可以有多少钱

    对比:http://codeforces.com/contest/867/problem/E

    分析

    此题感觉能挣钱就买卖,低进高出即可

    CF867E,一天只能买或者卖

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    int a[370];
    
    int main()
    {
        int n;
        scanf("%d", &n);
        for(int i=1;i<=n;i++)  scanf("%d", &a[i]);
        ll sum=100;
        for(int i=1;i<n;i++)
        {
            if(a[i+1]>a[i])
            {
                ll num=min(sum/a[i], 100000LL);
                sum=sum-num*a[i]+num*a[i+1];
            }
        }
        printf("%lld
    ", sum);
        return 0;
    }

    E Exponial

    数论题


    F Fleecing the Raffle    solved by czh&ym

    题意

    现在有n个人抽奖,共有p个奖,现在可以将任意数量自己的名字放入箱子里,问自己最大的中奖概率

    分析

    设添加x个自己,则中奖概率为 C(x,1) * C(n,p-1) / C(n+x,p)

    组合式推一下,化简一下不难看出规律,暴力找最大值即可


    G Game Rank  solved by czh   solved by ym

    题意

    模拟题

    分析

    ym:按题意模拟即可

    czh:题目很绕,没有很快理解出题意 by czh


    H Highest Tower

    DIfficult


    I Interception

    DIfficult


    J Jumbled Compass    solved by czh   solved by ym

    签到题


    K Keeping the Dogs Apart

    DIfficult


    Summary

    Ym:训练的时候很困=_=,没状态,还读错题了,坑了,和学弟一起训练体验很好呀

             读题能力不行,需要及时背单词,提升读题能力

             提升思维能力

    Czh:  英语水平要求很高,一两个关键单词认错往往这题就过不了

  • 相关阅读:
    深刻剖析spring三种注入方式以及使用注解的原理
    springcloud(一):大话Spring Cloud
    springcloud学习资料汇总
    springboot(一):入门篇
    springboot学习资料汇总
    jvm系列(七):如何优化Java GC「译」
    jvm系列(六):Java服务GC参数调优案例
    jvm系列(五):Java GC 分析
    jvm系列(四):jvm调优-命令篇
    android view、viewgroup 事件响应拦截处理机制
  • 原文地址:https://www.cnblogs.com/Deadline/p/8709047.html
Copyright © 2020-2023  润新知