NYIST-2019省赛训练个人积分赛第五场

A - An Equation

FZU - 1909

题目大意:
输入四个数字a,b,c,d是否其中两个数的和是否等于另外两个数的和
比赛的时候脑子瓦特了。。。。Yes打成了YES。。wa了一发。。。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
    int T;
    int a,b,c,d,p=1;
    scanf("%d",&T);
    while(T--)
    {
        int flag=0;
        scanf("%d %d %d %d",&a,&b,&c,&d);
        if(a+b==c+d)
            flag=1;
        else if(a+c==b+d)
            flag=1;
        else if(a+d==b+c)
            flag=1;
        printf("Case %d: ",p++);
        if(flag)
            printf("Yes\n");
        else
            printf("No\n");
    }
}

·
·

B - 非主流

FZU - 1922

鸭子a1在这三只鸭子里的另类度为:dist (a1,a1)+dist (a1,a2)+dist (a1,a3)。

定义dist运算为:

dist (a1,a1)= (|1-1|+|0-0|+|0-0|+|1-1|+|0-0|) = 0

dist (a1,a2) = (|1-0|+|0-1|+|0-0|+|1-0|+|0-1|) = 4;

dist (a1,a3) = (|1-0|+|0-0|+|0-1|+|1-0|+|0-1|) = 4;

就得到鸭子a1在这三只鸭子里的另类度为8。

另类的鸭子越多,风险就越大,因此,养鸭场的老板希望可以确定他的鸭群里面到底有多少另类的鸭子。

Input
首先第一行为T,表示有T组数据。接下来为每组数据的结构:
每组数据第一行为空格隔开的三个整数n、m和p。n表示有n只鸭子(2 <= n <= 10,000),m表示这群鸭子有m个特征值(5 <= m <= 200),p表示另类度的界限,认为大于等于p的另类度的鸭子就为另类的鸭子(0 <= p <= 2,000,000)。

接下来n行,每行有m个用空格隔开的0或1数字,表示鸭子的特征值。

Output
对于每组数据输出一行先输出组数(从1开始),接着输出该群鸭子中另类的鸭子数。
Sample Input
1
3 5 8
1 0 0 1 0
0 1 0 0 1
0 0 1 0 1
Sample Output
Case 1: 1

虽然说题意不太好理解,可是推一推也能推出来,先说思路吧:
n大概有10000,m有200,n2的复杂度是肯定不行的,分析一下题意,第一只鸭子的另类度也就是第一行和第二行,第一行和第三行特征值不一样的有几个,然而特征值只有0和1,所以每一列记录一下0和1的个数就好了
这道题。。。感觉全世界都想到了思路。。。只有我。。。卡死了。。。。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int e[10005][205];
int a[10005],b[10005];
int main()
{
    int n,m,P,p=1,T;
    scanf("%d",&T);
    while(T--)
    {
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        scanf("%d %d %d",&n,&m,&P);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&e[i][j]);
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(e[j][i]==0)
                    a[i]++;
                else
                    b[i]++;
            }
        }
        int sum=0;
        for(int i=1;i<=n;i++)
        {
            int ans=0;
            for(int j=1;j<=m;j++)
            {
                if(e[i][j]==0)
                    ans+=b[j];
                else
                    ans+=a[j];
            }
            if(ans>=P)
                sum++;
        }
        printf("Case %d: %d\n",p++,sum);
    }
    return 0;
}

·
·

C - Unusual Product

CodeForces - 405C

大概题意

给你一个n*n的矩阵,矩阵的值为矩阵自乘,然而每一步的值都要mod2,每次进行m次操作
操作有三种:
1) 1 x 将第x行的0 1都反转为1 0
2) 2 x 将第y列的0 1都反转为1 0
3)3 计算矩阵的自乘值

思路

我们设一个3*3的矩阵
a1 a2 a3
a4 a5 a6
a7 a8 a9
这个矩阵的自乘值为(a1 * a1)+(a2 * a4)+(a3 * a7)+(a2 * a4)+(a5 * a5)+(a8 * a6)+(a1 * a1)+(a6 * a8)+(a9 * a9);
整理一下等于:(a1 * a1)+(a5 * a5)+(a9 * a9)+2 *(a2 * a4)+2 (a3 * a7)+2 (a8 * a6)
也就是这个矩阵的自乘值只和a1 a5 a9有关,那么反转一次,只会改变这三个数中的其中一个,所以反转一次自乘值要么从0变为1,要么从1变为0,只需要判断反转的个数,反转个数为奇数,则自乘值改变,反转个数为偶数,则自乘值不变


#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int e[10005][205];
int a[10005],b[10005];
int main()
{
    int n,m,P,p=1,T;
    scanf("%d",&T);
    while(T--)
    {
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        scanf("%d %d %d",&n,&m,&P);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&e[i][j]);
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(e[j][i]==0)
                    a[i]++;
                else
                    b[i]++;
            }
        }
        int sum=0;
        for(int i=1;i<=n;i++)
        {
            int ans=0;
            for(int j=1;j<=m;j++)
            {
                if(e[i][j]==0)
                    ans+=b[j];
                else
                    ans+=a[j];
            }
            if(ans>=P)
                sum++;
        }
        printf("Case %d: %d\n",p++,sum);
    }
    return 0;
}

·
·

D - 填空

FZU - 1926

中文题意就不解释了。。。
就是KMP的板子题,要注意的是模式串中的 _ 是可以和任何单词匹配的
有点卡时间,用cin输入string都会超时,要用scnaf()输入再转成string

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
string b[1005],a[1005];
char s[10000];
int nex[1005],e;
void Nex(int n)
{
    int i=0,j=-1;
    nex[0]=-1;
    while(i<n)
    {
        if(j==-1||b[i]==b[j]||b[j]=="_"||b[i]=="_")
        {
            i++;
            j++;
            nex[i]=j;
        }
        else
            j=nex[j];
    }
}
int kmp(int n)
{
    Nex(n);
    int i=0,j=0;
    while(i<e&&j<n)
    {
        if(j==-1||a[i]==b[j]||b[j]=="_")
        {
            i++;
            j++;
        }
        else
            j=nex[j];
        if(j==n)
                return 1;
    }
    return 0;
}
int main()
{
    int T,n,p=1;
    scanf("%d",&T);
    while(T--)
    {
        int k=0;
        while(1)
        {
            scanf("%s",s);
            if(strcmp(s,"@")==0)
                break;
            a[k++]=(string)s;
        }
        e=k;
        scanf("%d",&n);
        printf("Case %d:\n",p++);
        while(n--)
        {
            k=0;
            while(1)
            {
                scanf("%s",s);
                if(strcmp(s,"@")==0)
                    break;
                b[k++]=(string)s;
            }
            if(kmp(k))
                printf("YES\n");
            else
                printf("NO\n");
        }
    }
    return 0;
}

·
·

E - 死锁

FZU - 1924

中文的题意。。很容易看懂,而且题中已经把思路说出来了,就是看自己能不能回到自己
让我有点惊讶的是,爆搜竟然过了。。。
先建图,建图之后枚举每个点,每个点开始搜,看能不能搜到自己

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int f[1005],tot,u,flag,vis[1005];
struct node
{
    int v,nex;
};
node e[1000005];
void add(int u,int v)
{
    e[tot].v=v;
    e[tot].nex=f[u];
    f[u]=tot++;
}
void dfs(int k)
{
    if(flag)
        return ;
    for(int i=f[k]; i!=-1; i=e[i].nex)
    {
        int v=e[i].v;
        if(v==u)
        {
            flag=1;
            return ;
        }
        if(!vis[v])
        {
            vis[v]=1;
            dfs(v);
        }
    }
}
int main()
{
    int T,p=1;
    int n,m,a,b;
    scanf("%d",&T);
    while(T--)
    {
        flag=0;
        tot=0;
        memset(f,-1,sizeof(f));
        int x,y;
        scanf("%d %d %d %d",&n,&m,&a,&b);
        for(int i=1; i<=a; i++)
        {
            scanf("%d %d",&x,&y);
            add(x,y+n);
        }
        for(int i=1; i<=b; i++)
        {
            scanf("%d %d",&x,&y);
            add(x+n,y);
        }
        for(int i=0; i<n+m; i++)
        {
            memset(vis,0,sizeof(vis));
            vis[i]=1;
            u=i;
            dfs(i);
            if(flag)
                break;
        }
        printf("Case %d: ",p++);
        if(flag)
            printf("Possible\n");
        else
            printf("Impossible\n");
    }
    return 0;
}

·
·

F - shadow

FZU - 2169

思路

比赛的时候想着跑最短路来着。。。算了一下感觉要超时,就没有打,但是好像spfa是可以过的,其实不用那么麻烦,我们从点1开始,广搜,把每个点的父亲节点都存储起来,然后再从那k个点往1节点回溯,还有一个可以剪枝的点就是,如果跑到了之前的点走过的节点,就不用往前搜了,因为走的路都是一样的。(刚开始的时候每个点的父亲节点是它自己)

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<math.h>
#include<vector>
#include<queue>
using namespace std;
int a[100005],f[100005],tot,vis[100005];
int g[100005],b[100005];
struct node
{
    int v,nex;
};
node e[500005];
void add(int u,int v)
{
    e[tot].v=v;
    e[tot].nex=f[u];
    f[u]=tot++;
}
void dfs()
{
    queue<int>q;
    q.push(1);
    vis[1]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=f[u];i!=-1;i=e[i].nex)
        {
            int v=e[i].v;
            if(!vis[v])
            {
                vis[v]=1;
                g[v]=u;
                q.push(v);
            }
        }
    }
}
int main()
{
    int n,m,x,y;
    while(~scanf("%d %d",&n,&m))
    {
        tot=0;
        memset(f,-1,sizeof(f));
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++)
          {
              g[i]=i;
              scanf("%d",&a[i]);
          }
        for(int i=1;i<=m;i++)
            scanf("%d",&b[i]);
        for(int i=1;i<=n-1;i++)
        {
            scanf("%d %d",&x,&y);
            add(x,y);
            add(y,x);
        }
        dfs();
        int ans=0;
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=m;i++)
        {
            int k=b[i];
            while(1)
            {
                if(vis[k]||k==1)
                    break;
                if(!vis[k])
                {
                    vis[k]=1;
                    ans+=a[k];
                }

                k=g[k];
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

·
·

G - Domino Effect

CodeForces - 405B

题意

题描述的是多米诺骨牌,输入的是行字符串只有三种字符‘L’,‘R’,‘.’如果是’.'意味着这里有一块多米诺骨牌,如果是‘R’意味着这个多米诺骨牌向右边倒,如果是‘L’意味着这个多米诺骨牌向左边倒,问你最后还剩多少张多米诺骨牌是直立着的(当左边右两遍的骨牌都向中间倒,如果两遍倒的骨牌数量是一样的,则这个骨牌是可以直立的)

思路

看了题之后感觉模拟过程有点复杂,在网上看到了一个思路感觉特别的好:用一个数组在记录这个骨牌左右两边倒的个数,向左倒就叠加加1,向右倒叠加减1
例如;
. . . L . . . R .L
数组记录为-3 -2 -1 L 0 0 0 R 0 L 数组中的数位0则说明这个骨牌是直立的

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
char s[3005];
int e[3005];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(e,0,sizeof(e));
        scanf("%s",s);
        for(int i=0;i<n;i++)
        {
            if(s[i]=='L')
            {
                for(int j=1,k=i-1;k>=0&&s[k]=='.';j++,k--)
                    e[k]+=j;
            }
            else if(s[i]=='R')
            {
                for(int j=1,k=i+1;k<n&&s[k]=='.';j++,k++)
                    e[k]-=j;
            }
        }
        int cnt=0;
        for(int i=0;i<n;i++)
        {
            if(e[i]==0&&s[i]=='.')
               {
                   //printf("%d\n",i);
                   cnt++;
               }
        }
        printf("%d\n",cnt);
    }
    return 0;
}

·
·

H - 栀子花开

FZU - 1921

题意就不解释了,看到题之后就觉得是个点更新的线段树,敲了一个板子就过了。。。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct node
{
    int id,sum;
};
node e[100005];
int a[10005];
void build(int root,int l,int r)
{
    if(l==r)
    {
        e[root].id=l;
        e[root].sum=a[l];
    }
    else
    {
        build(root*2,l,(l+r)/2);
        build(root*2+1,(l+r)/2+1,r);
        if(e[root*2].sum>e[root*2+1].sum)
        {
            e[root].sum=e[root*2+1].sum;
            e[root].id=e[root*2+1].id;
        }
        else
        {
            e[root].sum=e[root*2].sum;
            e[root].id=e[root*2].id;
        }
    }
}
void update(int x,int y,int l,int r,int root)
{
    if(l==r)
    {
        e[root].sum+=y;
    }
    else
    {
        if(x<=(l+r)/2)
            update(x,y,l,(l+r)/2,root*2);
        else
            update(x,y,(l+r)/2+1,r,root*2+1);
        if(e[root*2].sum>e[root*2+1].sum)
        {
            e[root].sum=e[root*2+1].sum;
            e[root].id=e[root*2+1].id;
        }
        else
        {
            e[root].sum=e[root*2].sum;
            e[root].id=e[root*2].id;
        }
    }
}
int main()
{
    int T,n,p=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
            scanf("%d",&a[i]);
        build(1,1,n);
        int m,x,y;
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d %d",&x,&y);
            if(x==0)
             x=e[1].id;
            update(x,y,1,n,1);
        }
        printf("Case %d: %d %d\n",p++,e[1].id,e[1].sum);
    }
    return 0;
}

·
·

I - Gravity Flip

CodeForces - 405A

题意

有n个长直柱体,每个直柱体都是由若干个小立方体摞起来的,刚开始的时候重力是向下的,这些小立方体都直立的排在一起,问你,当重力的方向改变为向右之后,每个直柱体上的小立方体有几个
啊。。。这个题是我的读题有问题吗。。比赛的时候,人家看了样例就猜出来题意了,我把题读了n遍才搞出来题意
就是个模拟。。。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[100];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
        scanf("%d",&a[i]);
    while(1)
    {
        int flag=0;
        for(int i=n-1; i>=1; i--)
        {
            int t=i;
            for(int j=i+1; j<=n; j++)
            {
                //printf("%d\n",j);
                if(a[i]>a[j])
                {
                    flag=1;
                    t=j;
                }
            }
            if(t>i)
            {
                int k=a[i]-a[t];
                a[i]-=k;
                a[t]+=k;
            }
        }
        if(!flag)
            break;
    }

    for(int i=1; i<=n; i++)
    {
        printf("%d%c",a[i],i==n?'\n':' ');
    }
    return 0;
}

·
·
这场比赛打的我心态崩崩的。。。。题都不是很难,但是就是打的不好,有些题没敢写,有些题卡出发际线。。。那个鸭子那个题(第二题)竟然没有写出来。。我的天啊。。。好难受。。。总结就是自己太菜了太菜了。。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值