zoukankan      html  css  js  c++  java
  • 2018 ICPC Asia Jakarta Regional Contest

    题目传送门

    题号 A B C D E F G H I J K L
    状态 Ο . . Ο . . Ø Ø Ο Ο . Ο

    Ο:当场

    Ø:已补

    .  :  待补

    A. Edit Distance

    Thinking:kk pai爷

    Code:kk

      不能直接反转,比如"010101",直接反转后就变成"101010",右移一位,然后加个0就可以了。

      所以要先统计01的数量,如果0大于1,就全变成1,1大于0,就全变成0(从数量上的改变就大于s/2了),相等的话,就看首位是0还是1,取相反,后面和首位不一样就行(位置)。

    #include<bits/stdc++.h>
    #include<tr1/unordered_map>
    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    #define fpn() freopen("simple.in","r",stdin)
    #define rd read()
    using namespace std;
    const int maxn=2010;
    typedef long long ll;
    int a,b;
    char s[maxn];
    int main(){
        cin>>s+1;
        int n=strlen(s+1);
        for(int i=1;i<=n;i++)
        {
            if(s[i]=='0')a++;
            else b++;
        }
        if(a>b){
            for(int i=1;i<=n;i++)
            {
                printf("1");
            }
            puts("");
        }else if(a<b){
            for(int i=1;i<=n;i++)
            {
                printf("0");
            }
            puts("");
        }else{
            if(s[1]=='1'){
                printf("0");
                for(int i=2;i<=n;i++)
                {
                    printf("1");
                }
                puts("");
            }else{
                printf("1");
                for(int i=2;i<=n;i++)
                {
                    printf("0");
                }
                puts("");
            }
        }
    } 
    View Code

    D. Icy Land

    Thinking:kk

    Code:pai爷

      首先我们考虑大一点的矩阵,对于$n*m$来说,中心的$(n-2)*(m-2)$的矩阵中,只要有冰地,这个冰地就必然到达不了,因为会直接划过去,所以我们要把中间这个矩阵直接变成"#",然后我们要确保外围的过道上有一个#能让我们进入中心区域。

      然后特殊考虑$2*n$的矩阵,还是中心的两行,只要上下有一个就可以了。

    #include<bits/stdc++.h>
    #include<tr1/unordered_map>
    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    #define fpn() freopen("simple.in","r",stdin)
    #define rd read()
    using namespace std;
    const int maxn=2010;
    typedef long long ll;
    int n,m,ans=0,flag;
    char s[510][510];
    void do1()
    {
        for(int i=2;i<=m-1;i++)
          if(s[1][i]=='.') ans++;
    }
    void do2()
    {
        for(int i=2;i<=n-1;i++)
          if(s[i][1]=='.') ans++;
    }
    void do3()
    {
        for(int i=2;i<=n-1;i++)
          if(s[i][1]!='#'&&s[i][2]!='#') ans++;
    }
    void do4()
    {
        for(int i=2;i<=m-1;i++)
          if(s[1][i]!='#'&&s[2][i]!='#') ans++;
    }
    void do5()
    {
        for(int i=2;i<=n-1;i++)
          for(int j=2;j<=m-1;j++)
             if(s[i][j]=='.') ans++;
        flag=1;
        for(int i=2;i<=m-1;i++)
           if(s[1][i]=='#'||s[n][i]=='#') flag=0;
        for(int i=2;i<=n-1;i++)
           if(s[i][1]=='#'||s[i][m]=='#') flag=0;
        ans+=flag;
    }
    void work()
    {
        if(n==1) do1(); 
        else if(m==1) do2(); 
        else if(m==2) do3(); 
        else if(n==2) do4();
        else do5();  
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
        work();
        printf("%d
    ",ans);
    }
    View Code

    F. Popping Balloons

    待补。 z

    G. Go Make It Complete

    补题:kk

      题意:给了一个无向图,要求你把这个无向图变成完全图,连边的条件是这条边的两个点的当前度数和大于等于k,问能变成完全图的最大的k是多少。

      思路:虽然AC了,但是感觉时间复杂度不太对。

      首先我们先把需要连的边处理出来,然后发现这个k是有可以二分的性质的,所以我们就二分k,每次把度数和大于等于k的边连上,更新度数,扫一遍这两个点连接的所有需要连的边,大于等于k的塞入队列,不断重复直到队列为空。类似拓扑排序。

      但是这样做的时间复杂度是$N3logn$,居然能过,,网上看到有人说可以用set维护边,但是细想感觉是不对的,所以比赛的时候,有这种看似过不了的算法,还是可以写一写的。

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    const int maxn=510;
    int mp[maxn][maxn],d[maxn],a[maxn][maxn],deg[maxn];
    int n,m;
    struct edge{
        int u,v;
    }b[maxn*maxn];
    int u,v,cnt;
    bool judge(int k)
    {
        memcpy(deg,d,sizeof(deg));
        memcpy(a,mp,sizeof(mp));
        queue<edge>q;
        for(int i=1;i<=cnt;i++)
        {
            int u=b[i].u,v=b[i].v;
            if(deg[u]+deg[v]>=k){
                a[u][v]=a[v][u]=1;
                q.push({u,v});
            }
        }
        while(!q.empty())
        {
            edge st=q.front();
            q.pop();
            int u=st.u,v=st.v;
            
            deg[u]++,deg[v]++;
            for(int i=1;i<=n;i++)
            {
                if(a[i][u]==0&&deg[i]+deg[u]>=k){
                    q.push({i,u});
                    a[i][u]=a[u][i]=1;
                }
                if(a[i][v]==0&&deg[i]+deg[v]>=k){
                    q.push({i,v});
                    a[i][v]=a[v][i]=1;
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            if(deg[i]!=n-1)return false;
        }
        return true;
    }
    int main(){
        while(cin>>n>>m)
        {
            clr(mp,0);
            clr(d,0);
            cnt=0;
            for(int i=1;i<=m;i++)
            {
                scanf("%d%d",&u,&v);
                mp[u][v]=mp[v][u]=1;
                d[u]++,d[v]++;
            }
            for(int i=1;i<=n;i++)
            {
                mp[i][i]=1;
                for(int j=i+1;j<=n;j++)
                {
                    if(mp[i][j]==0){
                        b[++cnt].u=i,b[cnt].v=j;
                    }
                }
            }
            int l=0,r=1000,mid,ans;
            while(l<r)
            {
                mid=(l+r)>>1;
                if(judge(mid)){
                    ans=mid,l=mid+1;
                }else{
                    r=mid;
                }
            }
            printf("%d
    ",ans);
        }
    }
    View Code

    H. Lexical Sign Sequence

      训练的时候想的似乎是正解?不过电脑在刚J题,没时间写

    补题:zz

           题意:给定一个只包含-1,0,1的数列,-1和1的位置的数不能改变,0的位置必须改变成-1或者1,并且使得改变后的数列满足k个条件,这k个条件都是一段区间里的数的和要大于等于某个数,如果这样的序列不存在就输出Impossible,否则输出字典序最小的序列。

           思路:可以根据初始的数列和每个给定的条件算出这k个区间每个区间最多有多少个-1(原本的-1不算),如果算出来的数量是小于0的,就肯定不存在;然后建立一个set,初始为空,根据最多能有都少个-1从小到大排序,枚举1到n位,枚举到第i位时,把不包含这个数的区间从set中删除,把起点为i的区间放到set里。如果原位子上的数为1或-1,就不动;如果set为空,这个位子上就放-1;如果set里有数,如果set里的第一个数大于0,就放-1,并且set里的数全减1,反之放1。

    //#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 c[100010], sum1[100010], sum2[100010], mp[100010], ans[100010];
    struct s
    {
        int a, b, c, d;
    }z[100010];
    struct ss
    {
        int a, f, d,id;
    }zz[200010];
    struct sss
    {
        int v, id;
        bool operator < (const sss &rhs) const
        {
            if (v == rhs.v)
            {
                return id < rhs.id;
            }
            return v < rhs.v;
        }
    };
    set<sss>st;
    inline bool comp(ss a, ss b)
    {
        if (a.a == b.a)
        {
            return a.f > b.f;
        }
        return a.a < b.a;
    }
    int main(void)
    {
        //ios::sync_with_stdio(false);
        int n, k, i, tmp, n1, n2, x, wz, qq, pos;
        bool flag;
        while (~scanf("%d %d", &n, &k))
        {
            sum1[0] = 0;
            sum2[0] = 0;
            st.clear();
            memset(mp, 0, sizeof(mp));
            for (i = 1; i <= n; i++)
            {
                scanf("%d", c + i);
                if (c[i] == 0)
                {
                    sum1[i] = sum1[i - 1];
                    sum2[i] = sum2[i - 1];
                }
                else if (c[i] == -1)
                {
                    sum1[i] = sum1[i - 1] + 1;
                    sum2[i] = sum2[i - 1];
                }
                else
                {
                    sum1[i] = sum1[i - 1];
                    sum2[i] = sum2[i - 1] + 1;
                }
            }
            flag = false;
            for (i = 0; i < k; i++)
            {
                scanf("%d %d %d", &z[i].a, &z[i].b, &z[i].c);
                zz[i].a = z[i].a;
                zz[i].f = -1;
                zz[i].id = i;
                zz[i + k].a = z[i].b + 1;
                zz[i + k].f = 1;
                zz[i + k].id = i;
                n1 = sum1[z[i].b] - sum1[z[i].a - 1];
                n2 = sum2[z[i].b] - sum2[z[i].a - 1];
                x = z[i].c - (n2 - n1);
                wz = z[i].b - z[i].a + 1 - n1 - n2;
                if (x > wz)
                {
                    flag = true;
                }
                else
                {
                    z[i].d = (wz - x) / 2;
                    zz[i].d = z[i].d;
                    zz[i + k].d = z[i].d;
                    //printf("z[i].d = %d
    ",z[i].d);
                }
            }
            if (flag)
            {
                printf("Impossible
    ");
                continue;
            }
            sort(zz, zz + k * 2, comp);
            qq = 0;
            pos = 0;
            /*for (i = 0;i < 2 * k;i++)
            {
                printf("   %d %d %d %d %d
    ",i,zz[i].a,zz[i].id,zz[i].d,zz[i].f);
            }*/
            for (i = 1; i <= n; i++)
            {
                while (pos < 2 * k && zz[pos].a == i)
                {
                    if (zz[pos].f == -1)
                    {
                        st.insert({ zz[pos].d + qq,zz[pos].id });
                        mp[zz[pos].id] = zz[pos].d + qq;
                    }
                    else
                    {
                        //printf("     %d %d
    ", i, st.empty());
                        st.erase({ mp[zz[pos].id],zz[pos].id });
                        //printf("     %d %d
    ",i,st.empty());
                    }
                    pos++;
                }
                if (st.empty())
                {
                    if (c[i] == 0)
                    {
                        //printf("ii = %d
    ",i);
                        ans[i] = -1;
                    }
                    else
                    {
                        //printf("iii = %d
    ", i);
                        ans[i] = c[i];
                    }
                }
                else if (c[i] == 0 && (*st.begin()).v - qq > 0)
                {
                    //printf("i = %d
    ",i);
                    qq++;
                    ans[i] = -1;
                }
                else if (c[i] == 0)
                {
                    //printf("iiiii = %d
    ", i);
                    ans[i] = 1;
                }
                else
                {
                    //printf("iiii = %d
    ", i);
                    ans[i] = c[i];
                }
            }
            for (i = 1; i <= n; i++)
            {
                printf("%d", ans[i]);
                if (i != n)
                {
                    printf(" ");
                }
            }
            printf("
    ");
        }
        return 0;
    }
    View Code

    I. Lie Detector

    Thinking

    Code:pai爷

      签到。

    #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,p;
    char s[100100][10];
    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);
        for(int i=1;i<=n;i++) scanf("%s",s[i]); 
    }
    void work()
    {
        if(s[1][0]=='L') p=0;
        else p=1;
        for(int i=2;i<=n;i++)
           if(s[i][0]=='L') p=!p;
        if(p==0) printf("LIE
    ");
        else printf("TRUTH
    ");
    }
    int main()
    {
        init();
        work();
    }
    View Code

    J. Future Generation

    题解:用F【I】【J】.c表示 处理到第i个字符串,能获得总长度为j的最小的子串(第i个字符串的子串),

          预处理q数组,每个字符串的子串。代码有点丑。

    #include<bits/stdc++.h>
    #include<tr1/unordered_map>
    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    #define fpn() freopen("simple.in","r",stdin)
    #define rd read()
    using namespace std;
    const int maxn=2010;
    typedef long long ll;
    
    struct node{
        char c[20];
        int l;
    }q[20][40000];
    
    struct nod{
        int p=0;
        char c[20];
    }f[20][400];
    
    int len[20],n,flag[20];
    char s[20][20],c[20][20];
    
    void work(int x)
    {
        int l=strlen(s[x]),z=0;
        for(int i=1;i<=(1<<l)-1;i++)
        {
            len[x]++;z=0;
            for(int k=0;k<l;k++)
            {
                if((i&(1<<k))!=0)
                {
    //                printf("i=%d k=%d
    ",i,k);
                    q[x][len[x]].c[++z]=s[x][k];
                }
            }
            q[x][len[x]].l=z;
    //        for(int j=1;j<=z;j++) printf("%c",q[x][len[x]].c[j]);
    //        printf("
    ");
        }
    }
    void init()
    {
        for(int i=1;i<=n;i++) work(i);
    }
    int check(int x,int j)
    {
        for(int i=1;i<=x;i++)
           if(f[1][x].c[i]>q[1][j].c[i]) return 1;
           else if(f[1][x].c[i]<q[1][j].c[i]) return 0;
           return 0;
    }
    void dodo()
    {
        for(int j=1;j<=len[1];j++) 
            {
                int len1=q[1][j].l;
                if(f[1][len1].p==0) 
                {
                    f[1][len1].p=1;
                    for(int k=1;k<=len1;k++) f[1][len1].c[k]=q[1][j].c[k];
                }
                else{
                    if(check(len1,j))
                    {
                        for(int k=1;k<=len1;k++) f[1][len1].c[k]=q[1][j].c[k];
                    }
                }
            }
        for(int i=2;i<=n;i++)
           for(int j=1;j<=16*16;j++)
           {
              if(f[i-1][j].p!=0)
              {
                      for(int i1=1;i1<=16;i1++)
                          for(int j1=1;j1<=i1;j1++)
                              c[i1][j1]='z';
                      for(int i1=1;i1<=16;i1++) flag[i1]=1; 
                      for(int k=1;k<=len[i];k++) 
                      {
                          int l=q[i][k].l;
                          if(strncmp(&(q[i][k].c[1]),&(f[i-1][j].c[1]), l)>0)
                          {
                               if(strncmp(&(c[l][1]),&(q[i][k].c[1]), l)>0)
                               {
                                     flag[l]=0;
                                     for(int kk=1;kk<=l;kk++) c[l][kk]=q[i][k].c[kk];
                             }
                        }
                      }
                      for(int pq=1;pq<=16;pq++)
                            if(flag[pq]==0)
                            {
    //                            printf("i=%d j=%d
    ",i,j);
    //                            for(int kk=1;kk<=pq;kk++) printf("%c",c[pq][kk]);
    //                            printf("
    ");
                                if(f[i][j+pq].p==0)
                                {
                                for(int kk=1;kk<=pq;kk++) 
                                     f[i][j+pq].c[kk]=c[pq][kk],f[i][j+pq].p=1;
                                }
                                else{
                                    if(strncmp(&(f[i][j+pq].c[1]),&(c[pq][1]), pq)>0)
                                    for(int kk=1;kk<=pq;kk++) 
                                     f[i][j+pq].c[kk]=c[pq][kk],f[i][j+pq].p=1;
                                }
                            
                            }
              }
           }
        int ans=-1;
        for(int i=1;i<=16*16;i++)
            if(f[n][i].p!=0) ans=i;
        printf("%d
    ",ans);
    }
    int main()
    {
        freopen("1.txt","r",stdin);
        freopen("1.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%s",s[i]);
        init();
        dodo();
    }
    View Code

    K. Boomerangs

    待补 k

    L:

      题意:给定一个只包含-1,0,1的数列,-1和1的位置的数不能改变,0的位置必须改变成-1或者1,并且使得改变后的数列满足k个条件,这k个条件都是一段区间里的数的和要大于等于某个数,如果这样的序列不存在就输出Impossible,否则输出字典序最小的序列。

           思路:可以根据初始的数列和每个给定的条件算出这k个区间每个区间最多有多少个-1(原本的-1不算),如果算出来的数量是小于0的,就肯定不存在;然后建立一个set,初始为空,根据最多能有都少个-1从小到大排序,枚举1到n位,枚举到第i位时,把不包含这个数的区间从set中删除,把起点为i的区间放到set里。如果原位子上的数为1或-1,就不动;如果set为空,这个位子上就放-1;如果set里有数,如果set里的第一个数大于0,就放-1,并且set里的数全减1,反之放1。

    #include<bits/stdc++.h>
    #include<tr1/unordered_map>
    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    #define fpn() freopen("simple.in","r",stdin)
    #define rd read()
    using namespace std;
    const int maxn=2010;
    typedef long long ll;
    char c[66];
    long long k,len;
    int v[66];
    inline long long f(void)
    {
        long long i,s = 0;
        for(i = 0;i < len;i++)
        {
            if(!v[i])
            {
                s *= 2;
                if(c[i] == '1')
                {
                    s += 1;
                }
            }
        }
        return s;
    }
    int main(){
        long long i;
        int ans;
        while(~scanf("%lld",&k))
        {
            scanf("%s",c);
            len = strlen(c);
            memset(v,0,sizeof(v));
            ans = 0;
            while(1)
            {
                if(f() <= k)
                {
                    break;
                }
                bool flag = true;
                for(i = 1;i < len;i++)
                {
                    if(c[i] == '1' && v[i] == 0)
                    {
                        v[i] = 1;
                        flag = false;
                        break;
                    }
                }
                if(flag)
                {
                    for(i = 1;i < len;i++)
                    {
                        if(c[i] == '0' && v[i] == 0)
                        {
                            v[i] = 1;
                            break;
                        }
                    }
                }
                ans++;
            }
            printf("%d
    ",ans);
        }
    }
    View Code

    总结:

      kk:今天比赛中途吃了个外卖(下课食堂人太多了吧)。所以中间稍微耽搁了一下下,A题一眼想到假算法,发现wa了那么多,所以等了等,果然hack了假算法,和pai爷讨论后ac,吃外卖的时候看了d题,回来稍微画了画想到正解,pai爷写的代码。后面的题目和zz、pai爷分别讨论了两道题,一道题感觉时间复杂度不对,没写完就让电脑了,一道题和zz讨论的似乎是正解,时间不够了没写。今天主要是被代码实现能力卡住了,还有没有提早提醒队友卡题的时候看新题,本来H题应该是能做的。

      pai爷:喵喵喵?口胡选手?我好菜啊?字符串的操作不会?努力!

      zz:去晚了一点,写了个L,J写完以后发现搜索写崩了,还不如直接二进制枚举,H想了个贪心,没时间写了。

  • 相关阅读:
    QPS/TPS的预估
    tornado多进程模式不同进程写不同日志
    [python]pypy优化python性能
    [linux]查看进程占用内存
    [linux]杀死同一个应用的所有进程
    [LINUX] 快速回收连接
    jdbc批量写入
    Android 手机卫士--参照文档编写选择器
    Android 手机卫士--导航界面1的布局编写
    Android 手机卫士--设置界面&功能列表界面跳转逻辑处理
  • 原文地址:https://www.cnblogs.com/mountaink/p/10472719.html
Copyright © 2011-2022 走看看