Codeforces Round #234 (Div. 2) <全>

CF 400A. Inna and Choose Options

题目链接:
http://codeforces.com/problemset/problem/400/A

题目意思:
给只含‘X'和’O'字符的长度为12的字符串,将它写入矩阵a*b(a*b=12)中,问存在某一列全为‘X'的矩阵的个数。

解题思路:
枚举。一共只有1*12,2*6,3*4,4*3,6*2,12*1六种。

代码:

//#include<CSpreadSheet.h>

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

char save[25];
int a[10]={0,1,2,3,4,6,12}; //保存六种情况
vector<int>myv;

int main()
{
   //freopen("in.txt","r",stdin);
   //freopen("out.txt","w",stdout);
   int t;

   scanf("%d",&t);
   while(t--)
   {
       myv.clear();
       scanf("%s",save+1);

       int ans=0;

       for(int i=1;i<=6;i++)
       {
           int aa=a[i];
           int bb=12/a[i];

           bool flag=false;

           for(int j=1;j<=bb;j++)
           {
               bool tt=true;
               for(int k=1;k<=aa;k++)
               {
                   if(save[(k-1)*bb+j]!='X')
                   {
                       tt=false;
                       break;
                   }
               }
               if(tt)
               {
                   flag=true;
                   break;
               }

           }
           if(flag)
           {
               ans++;
               myv.push_back(a[i]);//保存结果集
           }
       }
       printf("%d ",ans);
       for(int i=0;i<myv.size();i++)
            printf("%dx%d ",myv[i],12/myv[i]);
       putchar('\n');


   }
   return 0;
}






CF 400B. Inna and New Matrix of Candies

题目链接:

http://codeforces.com/contest/400/problem/B

题目意思:

给n*m的方格,每行中都且仅有一个方格含S和G,每一步可以使所有的G向右移,只到发生下列情况:1、某个G已到了最后一列。2、某个G已到了S。求把所有的G已到S需要的最少的步数。

解题思路:

统计S-G差出现的个数。

代码:

//#include<CSpreadSheet.h>

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define Maxn 1100

char save[Maxn][Maxn];
int n,m;
int gap[Maxn];

int main()
{
   //freopen("in.txt","r",stdin);
   //freopen("out.txt","w",stdout);
   while(~scanf("%d%d",&n,&m))
   {
       bool flag=true;

       memset(gap,0,sizeof(gap));

       for(int i=1;i<=n;i++)
       {
           scanf("%s",save[i]+1);
           int g,s;
           for(int j=1;j<=m;j++)
           {
               if(save[i][j]=='G')
                    g=j;
               else if(save[i][j]=='S')
                    s=j;

           }
           if(g>s)
                flag=false;
           else
                gap[s-g]++;

       }

       if(!flag)
       {
           printf("-1\n");
           continue;
       }
       int ans=0;

       for(int i=1;i<=m;i++)
            if(gap[i])
                ans++;
       printf("%d\n",ans);
   }
   return 0;
}

CF 400C C. Inna and Huge Candy Matrix

题目链接:

http://codeforces.com/problemset/problem/400/C

题目意思:

给一个矩阵,求经过顺时针旋转90度x次,左右翻转y次,逆时针旋转90度z次,坐标(x,y)对应的新坐标。

解题思路:

上面三种变换可以统一成几个简单的基本操作。详细可以参考我的这篇博客:http://blog.csdn.net/cc_again/article/details/18007891

这题相对比较简单,可以先对x%=4,y%=2,z=(4-z%4)%4(转化成顺时针的情况),然后对于每个坐标,分别实行上述操作,即可得到答案。

代码:

//#include<CSpreadSheet.h>

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

int n,m;
int tempn,tempm;

void C90(int &x,int &y) //顺时针旋转90度
{
    int temp=x;

    x=y;
    y=tempn-temp+1;

    swap(tempn,tempm);
}
void hh(int &x,int &y) //左右翻转
{
    y=tempm-y+1;
}
int main()
{
   //freopen("in.txt","r",stdin);
   //freopen("out.txt","w",stdout);
   int x,y,z,p;

   while(~scanf("%d%d",&n,&m))
   {
       scanf("%d%d%d%d",&x,&y,&z,&p);
       x=x%4; //顺时针的次数
       z=(4-z%4)%4; //转化为顺时针的次数
       y=y%2; //左右翻转

       for(int i=1;i<=p;i++)
       {
           int a,b;

           scanf("%d%d",&a,&b);
           tempn=n,tempm=m;

           for(int i=1;i<=x;i++)
                C90(a,b);
           if(y)
               hh(a,b);

           for(int i=1;i<=z;i++)
               C90(a,b);
           printf("%d %d\n",a,b);



       }

   }

   return 0;
}

CF 400 D D. Dima and Bacteria

题目链接:

http://codeforces.com/problemset/problem/400/D

题目意思:

这题意思有点搞人,有k种细菌,第i种有ci个,按顺序编号,一共有n个细菌。告诉细菌之间传递能量所需的价值。问是否存在对于任何种类i,该种所有细菌相互传递能量的价值都为0(可以传递)。存在就输出Yes,并输出任意两种细菌传递能量的最小值,否则只用输出No.

解题思路:

floyd+并查集+二分

如果价值为零,则添加到一个集合里,如果同种的细菌的fa相同,则说明该种细菌之间传递价值都为0。

对于不同种类的细菌,更新种类之间传递的最小值,用floyd求出任意两种之间的能量传递最小值。

sum[i]:保存第i种细菌的最后一个细菌编号,二分可以求出属于第几种细菌。

代码:

//#include<CSpreadSheet.h>

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define Maxn 110000
#define Maxm 550

int sum[Maxn],save[Maxm];
int n,m,k;
int fa[Maxn],dis[Maxm][Maxm];

void init()
{
    for(int i=1;i<=n;i++)
        fa[i]=i;
    memset(dis,INF,sizeof(dis));
    for(int i=1;i<=k;i++)
        dis[i][i]=0;
}

int find(int x)
{
    if(fa[x]!=x)
       return  fa[x]=find(fa[x]);
    return x;
}
int main()
{
   //freopen("in.txt","r",stdin);
   //freopen("out.txt","w",stdout);
   while(~scanf("%d%d%d",&n,&m,&k))
   {
       init();
      sum[0]=0;

      for(int i=1;i<=k;i++)
      {
          scanf("%d",&save[i]);
          sum[i]=sum[i-1]+save[i];
      }

      for(int i=1;i<=m;i++)
      {
          int a,b,c;
          int fa_a,fa_b,loc_a,loc_b;

          scanf("%d%d%d",&a,&b,&c);
          loc_a=lower_bound(sum+1,sum+k+1,a)-sum; //求出该细菌所属种类
          loc_b=lower_bound(sum+1,sum+k+1,b)-sum;


          if(loc_a!=loc_b) //说明不是同一种
             dis[loc_a][loc_b]=dis[loc_b][loc_a]=min(dis[loc_a][loc_b],c);

          if(c==0)
          {
              fa_a=find(a);
              fa_b=find(b);

              if(fa_a!=fa_b)
                  fa[fa_b]=fa_a;
          }



      }
      bool ans=true;

      for(int i=1;i<=k;i++)
      {
          int temp=find(sum[i-1]+1); //该种第一个细菌所在集合
          bool flag=true;

          for(int j=sum[i-1]+2;j<=sum[i];j++) //
          {
              if(find(j)!=temp)
              {
                  flag=false;
                  break;
              }
          }
          if(!flag)
          {
              ans=false;
              break;
          }
      }
      if(!ans)
      {
          printf("No\n");
          continue;
      }
      printf("Yes\n");
      for(int p=1;p<=k;p++) //floyd
            for(int i=1;i<=k;i++)
              {
                  for(int j=1;j<=k;j++)
                  {
                      if(dis[i][p]+dis[p][j]<dis[i][j])
                          dis[i][j]=dis[j][i]=dis[i][p]+dis[p][j];
                  }
              }
      for(int i=1;i<=k;i++)
      {
          for(int j=1;j<=k;j++)
          {
              if(dis[i][j]==INF)
                    printf("-1 ");
              else
                    printf("%d ",dis[i][j]);
          }
          putchar('\n');
      }


   }
   return 0;
}



CF 400 E E. Inna and Binary Logic

题目链接:

http://codeforces.com/problemset/problem/400/E

题目意思:

给定n个数a1[1..n],定义ak[i]=ak-1[i]&ak-1[i+1],则一共有n*(n-1)/2个数。有m种操作,每种操作ai,bi,表示把a1[ai]改成bi,求这n*(n-1)/2个数的和,改变是连续影响的。

解题思路:

二进制和数据结构。

按位进行处理,mys[i]表示第i位为零是n个数中的哪几个。两个零之间一定是连续的1,扫描开始的n个数,对于每一位如果它为1,则找到大于它的第一个为0的位置,则这个1持续的次数就是他们之间的间隔。这样求出原始的总和。

操作主要分两种:

1、把当前位的0变成1。此时从当前的0到下一个0的间距是该位0所要增加的1的个数p,该零后面的将不受影响。该零前面的所有连续的1(假设为m个)都会增加p个。(从0往左下角45度对角线)故+m*p*位权。

2、把当前位的1变成0。与上述情况相反,-m*p*位权。

注意要连续更新原始数组,中间溢出情况。

代码:

//#include<CSpreadSheet.h>

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define Maxn 110000
set<int>mys[20]; //mys[i]保存第i位为零有哪几个数
int save[Maxn];

int main()
{
    //cout<<(1<<20);
   //freopen("in.txt","r",stdin);
   //freopen("out.txt","w",stdout);
   int n,m;

   while(~scanf("%d%d",&n,&m))
   {
       for(int i=0;i<20;i++)
       {
           mys[i].clear();
           mys[i].insert(0); //边界情况考虑进去
           mys[i].insert(n+1);
       }
       for(int i=1;i<=n;i++)
       {
           scanf("%d",&save[i]);
           for(int j=0;j<20;j++)
           {
               if(!(save[i]&(1<<j)))
                    mys[j].insert(i); //统计j位为0的 哪几个情况
           }

       }
       ll ans=0;

       for(int i=1;i<=n;i++)
       {
           for(int j=0;j<20;j++)
           {
               if(save[i]&(1<<j)) //非零的情况
               {
                   set<int>::iterator it=mys[j].upper_bound(i); //找到大于当前位置的第一个零的位置

                   ans+=(ll)(*it-i)*(1<<j);
               }
           }
       }
       //printf("%I64d\n",ans);
       //system("pause");

       for(int i=1;i<=m;i++)
       {
           int ri,va;

           scanf("%d%d",&ri,&va);

           for(int j=0;j<20;j++)
           {
               if((va&(1<<j))&&((save[ri]&(1<<j))==0)) //要把0改成1
               {
                   set<int>::iterator it=mys[j].find(ri);

                   it++;
                   int rr=*it;
                   it--;
                   it--;
                   int le=*it;

                   ans+=(ll)(rr-ri)*(1<<j)*(ri-le);

                   mys[j].erase(ri);
               }
               else if(((va&(1<<j))==0)&&(save[ri]&(1<<j))) //把1变成0
               {
                   mys[j].insert(ri);
                   set<int>::iterator it=mys[j].find(ri);

                   it++;
                   int rr=*it;
                   it--;
                   it--;
                   int le=*it;

                   ans-=(ll)(rr-ri)*(1<<j)*(ri-le);


               }

           }
           printf("%I64d\n",ans);
           save[ri]=va; //注意连续更新
       }


   }


   return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值