Codeforces Round #234 (Div. 2)

           CF回滚以后掉到蓝名了,打了一场勉强回到div1,D最后复测竟然挂了,好伤心。。。

A Inna and Choose Options

         长度为12的OX的序列,要排成a×b的矩阵,使得矩阵有一列全为X。很简单。随便枚举一下就行了。。


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
char str[20];
char tmp[20][20];
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int t;
    scanf("%d",&t);
    vector<pair<int,int> >ans;
    while(t--)
    {
        scanf("%s",str);
        ans.clear();
        for(int b=12;b>=1;--b)
        {
            if(12%b!=0) continue;
            int a=12/b;
            bool flag=false;
            for(int j=0;j<b;++j)
            {
                bool canit=true;
                for(int i=0;i<a;++i)
                    if(str[i*b+j]!='X') {canit=false;break;}
                if(canit) {flag=true;break;}
            }
            if(flag) ans.push_back(make_pair(a,b));
        }
        int size=ans.size();
        printf("%d",size);
        for(int i=0;i<size;++i)
        {
            printf(" %dx%d",ans[i].first,ans[i].second);
        }
        printf("\n");
    }
    return 0;
}



B - Inna and New Matrix of Candies

         这题最开始看了半天楞是没看懂,只要先去做C。。。其实就是给出一个矩阵,每一行只有一个G和一个S其他都是*,现在要把每一行的G都移动到S处。每次可以选若干行,使这一行的G同时向右移动,直到有一个G到达S或到达矩阵最右段。问最少需要多少操作。。先算一下每个G到达S的步数,接下来让离得最近的到达S,同时所有的G移动,然后让离得第二近的移动……只要排个序搞一下就行了。


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=1000+10;
char str[maxn][maxn];
int step[maxn];
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;++i)
        scanf("%s",str[i]);
    bool cansolve=true;
    for(int i=0;i<n;++i)
    {
        bool flag=false;
        int last=-1;
        for(int j=0;j<m;++j)
        {
            if(str[i][j]=='G')
                {last=j;flag=true;}
            else if(str[i][j]=='S')
            {
                if(last==-1) break;
                step[i]=j-last;
            }
        }
        if(!flag) {cansolve=false;break;}
    }
    if(!cansolve)
        printf("-1\n");
    else
    {
        int cnt=0;
        sort(step,step+n);
        int k=n;
        while(true)
        {
            cnt++;
            int val=step[0];
            int i=1;
            for(i=1;i<k;++i)
                step[i]-=val;
            step[0]=0;
            i=0;
            while(step[i]==0&&i<k) i++;
            if(i==k) break;
            for(int j=0;j<k-i;++j)
                step[j]=step[i+j];
            k=k-i;
        }
        printf("%d\n",cnt);
    }
    return 0;
}

C - Inna and Huge Candy Matrix

      给出一个n×m的矩阵,有p个位置有糖果,现在将这个矩阵顺时针旋转x次,翻转矩阵的行y次,逆时针旋转z次,问最后这p个点的位置。在纸上画一画就会发现每个操作后的位置都可以算出来,这样,将x,y,分别对4,2,4取模,然后依次模拟相应操作计算坐标就行了。


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
struct Point
{
    int x,y;
    Point(){}
    Point(int x,int y):x(x),y(y) {}
}pt[maxn];
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n,m,X,Y,Z,p;
    scanf("%d%d%d%d%d%d",&n,&m,&X,&Y,&Z,&p);
    for(int i=0;i<p;++i)
        scanf("%d%d",&pt[i].x,&pt[i].y);
    X=X%4;Y%=2;Z%=4;
    int N=n,M=m;
    for(int i=0;i<p;++i)
    {
        n=N,m=M;
        int x=pt[i].x,y=pt[i].y;
        if(X==1) pt[i]=Point(y,n-x+1),swap(n,m);
        else if(X==2) pt[i]=Point(n-x+1,m-y+1);
        else if(X==3) pt[i]=Point(m-y+1,x),swap(n,m);
        x=pt[i].x,y=pt[i].y;
        if(Y) pt[i]=Point(x,m-y+1);
        x=pt[i].x,y=pt[i].y;
        if(Z==3) pt[i]=Point(y,n-x+1);
        else if(Z==2) pt[i]=Point(n-x+1,m-y+1);
        else if(Z==1) pt[i]=Point(m-y+1,x);
        printf("%d %d\n",pt[i].x,pt[i].y);
    }
    return 0;
}


D - Dima and Bacteria

       感觉这题也好难理解。。。有n个细菌,将这些细菌分为k种,每种有c[i]个,接下来有m条边表示从某个细菌到另一个细菌所需要耗费的能量。如果同种细菌之间任意两个细菌相互到达所需要的能量为0,那么就输出yes并输出不同种类细菌之间的最短距离。需要注意两个同种细菌可以经过其他不同种类的细菌到达。理解题意以后就比较简单了,如果边权为0,那么用并查集把这两个点合并,最后看相同种类的细菌是否都在同一个集合中。最后floyd一下就行了。


代码:


#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
struct Edge
{
    int v,w,next;
    Edge(){}
    Edge(int v,int w,int next):v(v),w(w),next(next){}
}edges[maxn<<1];
int head[maxn],nEdge;
int type[maxn],c[maxn];
int pa[maxn];
int d[550][550];
void AddEdges(int u,int v,int w)
{
    edges[++nEdge]=Edge(v,w,head[u]);
    head[u]=nEdge;
    edges[++nEdge]=Edge(u,w,head[v]);
    head[v]=nEdge;
}
int Find(int x)
{
    return x==pa[x]?x:pa[x]=Find(pa[x]);
}
void Uion(int x,int y)
{
    int a=Find(x),b=Find(y);
    if(a!=b) pa[b]=a;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    int cnt=0,u,v,w;
    memset(head,0xff,sizeof(head));
    memset(d,0x3f,sizeof(d));
    nEdge=-1;
    for(int i=1;i<=n;++i) pa[i]=i;
    for(int i=1;i<=k;++i)
    {
        scanf("%d",&c[i]);
        for(int j=0;j<c[i];++j)
            type[++cnt]=i;
    }
    for(int i=0;i<m;++i)
    {
        scanf("%d%d%d",&u,&v,&w);
        AddEdges(u,v,w);
        if(w==0)
            Uion(u,v);
        if(type[u]!=type[v])
            d[type[u]][type[v]]=d[type[v]][type[u]]=min(d[type[u]][type[v]],w);
    }
    cnt=1;
    bool flag=true;
    for(int i=1;i<=k&&flag;++i)
    {
        int fa=Find(cnt);
        for(int j=0;j<c[i];++j)
            if(Find(cnt+j)!=fa) {flag=false;break;}
        cnt+=c[i];
    }
    if(!flag)
        printf("No\n");
    else
    {
        for(int i=1;i<=k;++i) d[i][i]=0;
        for(int v=1;v<=k;++v)
            for(int i=1;i<=k;++i)
                for(int j=1;j<=k;++j)
                    d[i][j]=min(d[i][j],d[i][v]+d[v][j]);
        printf("Yes\n");
        for(int i=1;i<=k;++i)
        {
            for(int j=1;j<=k;++j)
            {
                if(j!=1) printf(" ");
                if(d[i][j]==inf) d[i][j]=-1;
                printf("%d",d[i][j]);
            }
            printf("\n");
        }
    }
    return 0;
}

E - Inna and Binary Logic

       最初给出n个序列,对序列要进行n-1次操作,每次令ai[k] = ai - 1[kAND ai - 1[k + 1].问所有操作过程中的序列的和。开始没什么思路,看了看过掉的代码,发现完全看不懂这些大牛们的高大上的方法,不过也有所启发,yy了一下,想了个麻烦的方法、、、、首先把每个数按位建17棵线段树,对于每一位,将整个操作列出来可以发现,如果这个序列每有连续k个1,那么最终操作的总和就要加上(k+1)*k/2。想了想,利用线段树区间合并的方法貌似能搞,val[]表示操作完这个区间后的总和,sum[]表示区间里1的个数,pre[]表示区间最长连续1的前缀数,suff[]表示区间最长连续的1的后缀数。然后用线段树维护即可。。。


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
int num[maxn];
struct SegTree
{
    int sum[maxn<<2],pre[maxn<<2],suff[maxn<<2];
    ll val[maxn<<2];
    int bitp;
    void PushUp(int l,int r,int rt)
    {
        int m=(l+r)>>1;
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
        if(sum[rt<<1]==m-l+1)
            pre[rt]=sum[rt<<1]+pre[rt<<1|1];
        else pre[rt]=pre[rt<<1];
        if(sum[rt<<1|1]==r-m)
            suff[rt]=suff[rt<<1]+sum[rt<<1|1];
        else
            suff[rt]=suff[rt<<1|1];
        if(suff[rt<<1]&&pre[rt<<1|1])
        {
            val[rt]=val[rt<<1]+val[rt<<1|1];
            ll tmp=suff[rt<<1];
            val[rt]-=tmp*(tmp+1)/2;
            tmp=pre[rt<<1|1];
            val[rt]-=tmp*(tmp+1)/2;
            tmp=suff[rt<<1]+pre[rt<<1|1];
            val[rt]+=tmp*(tmp+1)/2;
        }
        else
            val[rt]=val[rt<<1]+val[rt<<1|1];
    }
    void build(int l,int r,int rt)
    {
        if(l==r)
        {
            val[rt]=sum[rt]=pre[rt]=suff[rt]=(num[l]>>bitp)&1;
            return ;
        }
        int m=(l+r)>>1;
        build(l,m,rt<<1);
        build(m+1,r,rt<<1|1);
        PushUp(l,r,rt);
    }
    void Update(int p,int l,int r,int rt,int v)
    {
        if(l==r)
        {
            sum[rt]=val[rt]=pre[rt]=suff[rt]=v;
            return ;
        }
        int m=(l+r)>>1;
        if(m>=p) Update(p,l,m,rt<<1,v);
        else Update(p,m+1,r,rt<<1|1,v);
        PushUp(l,r,rt);
    }
}tree[17];
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
        scanf("%d",&num[i]);
    for(int i=0;i<17;++i)
    {
        tree[i].bitp=i;
        tree[i].build(1,n,1);
    }
    int p,v;
    ll sum;
    while(m--)
    {
        scanf("%d%d",&p,&v);
        sum=0;
        for(int i=0;i<17;++i)
        {
            tree[i].Update(p,1,n,1,(v>>i)&1);
            sum+=(1<<i)*tree[i].val[1];
        }
        printf("%I64d\n",sum);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值