Contest - 2017年浙江理工大学程序设计竞赛校赛

点击:http://oj.acm.zstu.edu.cn/JudgeOnline/contest.php?cid=3650

Problem A: 回文

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 1637   Solved: 505

Description

小王想知道一个字符串是否为 ABA’ 型字符串。 ABA’ 型字符串的定义: S=ABA’ A B A’ 都是原字符串的子串 ( 不能是空串), A’ 的意思是 A 的反转串, B 不一定要和 A A’ 不同。符合 ABA’ 型的例如: " aba”"acbbca”"abcefgcba”等。"Abcefgcba”ABA’ 型,因为它能找到一组对应的 A "abc”) B(”efg”) A’("cba") 满足定义。

Input

第一行给测试总数 T(T <= 1000) ,接下来有 T 组测试数据。
每组测试数据有一行字符串 S(1 <= |S| <= 50000) ,字符串保证只有小写或大写英文字母。

Output

每组测试数据输出一行,如果 S ABA’ 型字符串,输出 "YES” ,否则输出 "NO"

Sample Input

5
abA
gg
Codeforces
acmermca
myacm

Sample Output

NO
NO
NO
YES
YES
题解:字符串

WA了三遍的水题。字符串处理,把题读全了就可以了。我是分的奇偶长度,分别考虑的,这样清晰点

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

char s[600050];

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",s);
        int len=strlen(s);
        if(len==1)
        {
            printf("NO\n");
            continue;
        }
        int i,j;
        if(len%2==0)
        {
            i=0;
            j=len-1;
            while(i<j)
            {
                if(s[i]==s[j])
                {
                    i++;
                    j--;
                }
                else break;
            }
            if(s[0]==s[len-1]&&len>2)
            {
                printf("YES\n");
            }
            else printf("NO\n");
        }
        else
        {
            i=0;
            j=len-1;
            while(i<j)
            {
                if(s[i]==s[j])
                {
                    i++;
                    j--;
                }
                else break;
            }
            if(s[0]==s[len-1])
            {
                printf("YES\n");
            }
            else printf("NO\n");
        }
    }
    return 0;
}



Problem I: 约素

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 1809  Solved: 469

Description

判断一个正整数n的约数个数是否为p,其中p是素数。

Input

第一行给测试总数T(T <= 10000)。

接下来有T行,每行有两个数字n(1 <= n <= 1000000000)和p(2 < p <= 1000000000)。

Output

每组测试数据输出一行,如果n的约数个数是p,输出“YES”,否则输出“NO”。

Sample Input

5
64 7
911 233
1080 13
1024 11
20170211 1913

Sample Output

YES
NO
NO
YES
NO

题解:暴力求约数,常规技巧简化

约数,我都想问到底什么叫做约数。以前做的计算约数的个数的理解记得不是这样的来。这个题的约数就是让你暴力找一遍n%i==0时i的个数。而紫书上的约数的个数是表示质因子的个数相乘得来的。

当然这个也不能1-n暴力,因为对于n%x==0的话,也就得出了另一个约数:y=n/x,既然是约数,x,y都是小于n的,那么x从1开始一直到,n/x就可以了,此时当x增大的时候,n/x就在减小。知道x>=n/x.特别处理,当x==n/x的时候约数的个数+1,否则+2(x和n/x都是n的约数)

#include<bits/stdc++.h>

using namespace std;

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,p;
        int sum;
        scanf("%d%d",&n,&p);
        sum=0;
        for(int i=1;i<=n/i;i++)
        {
            if(n%i==0)
            {
                sum++;
                if(i!=n/i)sum++;
            }
        }
        if(n==1)sum=1;
        //cout<<sum<<endl;
       if(sum==p)printf("YES\n");
       else printf("NO\n");
    }
    return 0;
}



Problem D: 买iphone

Time Limit: 3 Sec   Memory Limit: 128 MB
Submit: 1719   Solved: 316

Description

自从上次仓鼠中了1000万彩票后,彻底变成了土豪了,一群人愿意认他做干爹,仓鼠决定送他的干儿子每人一部iphone。仓鼠今天带了一群人去买iphone,每个人身上都背着一个大背包,只有3种背包,分别能装a,b,c个iphone,仓鼠希望每个人都能用iphone装满自己的背包。仓鼠有n个干儿子,也就是要买n部手机,仓鼠带了k个人去买手机,问是否存在一种情况能让每个买iphone的人的背包都装满

Input

输入包含多组测试数据,每组一行,包含5个整数n, k, a, b, c
(1 <= n, k , a, b, c <= 10000)
abc可以相同

Output

如果存在输出Yes,否则输出No

Sample Input

10 3 3 3 4
20 7 1 1 1
80 3 100 3 3
15 4 3 5 6

Sample Output

Yes
No
No
Yes

HINT

样例一3个人分别带大小为 3 3 4的背包去买手机正好每个人都装满

样例二 很明显只有一种背包,全部都是1也无法买20部iphone

样例四 4个人分别带大小为 3 3 3 6的背包去买手机正好每个人都装满
题解:暴力

没想到这个题纯暴力就能过了,当然了不是k^2级别的。一共有k个人去装手机,假设有x个人装a,y(y小于k-x)个人装b,剩下的人装c,只要判断出x*a+y*b+(k-x-y)*c==n的情况就可以了

#include<bits/stdc++.h>

using namespace std;

int main()
{
    int n,k,a,b,c;
    while(~scanf("%d%d%d%d%d",&n,&k,&a,&b,&c))
    {
        int flag=0;
        for(int i=0;i<=k;i++)
        {
            for(int j=0;j<=k-i;j++)
            {
                if(a*i+b*j+c*(k-i-j)==n)
                {
                    flag=1;
                    break;
                }
                if(flag)break;
            }
        }
        if(flag)printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}


Problem E: 同源数

Time Limit: 3 Sec   Memory Limit: 128 MB
Submit: 1288   Solved: 224

Description

如果x和y的质因子集合完全相同,那么我们就说他们是同源的。
比如说18 = 2 * 3 2,12 = 3 * 2 2

Input

本题有多组数据(组数 <= 555555)。
每组数据输入形如:
x y
x, y为整数(1 <= x, y <= 1e18)

Output

输出形入:
ans
如果x, y为同源数,那么ans为”Yes”, 不然为”No”.

Sample Input

18 12
2 3

Sample Output

Yes
No
题解:数论,唯一分解定理,gcd(),

这个题是分析的时间最长的一个题了,最后想出解法后还因为没考虑到全面的情况,又花了很长的时间。首先读完题目的第一反应就是唯一分解定理,然后就卡壳了。突然想到了gcd(),就在纸上分析了一下,慢慢的才ac的。

同源数,也就是他们的质因子的元素是相同的(个数不一定相同)。假如a=2*3*3*5*7,b=2*2*3*5*5*7,他们两个是同源数,对a,b求gcd(a,b)=g;显然g分解后质因子一定包含他们共有的质因子,即2*3*5*7,然后a,b都除以他们的质因子,如果两个数是同源数的话,那么让a一直除以a和g的gcd(),a=a/gcd(a,g),直到a==1或gcd(g,a)为止,如果a==1的说说明了a的质因子只包含了和g相同的质因子,如果a!=1&&gcd(a,g)==1的话,说明a和g互素,也就是a中的质因子有和g中的质因子不同的元素。同理对b也这样处理。如果a==1&&b==1的话说明是同源数,否则不是。

特殊处理a==b和a==1||b==1的情况。

#include<bits/stdc++.h>

using namespace std;
unsigned long long gcd(unsigned long long a,unsigned long long b)
{
    return b==0?a:gcd(b,a%b);
}
int main()
{
    unsigned long long x,y;
    while(~scanf("%lld%lld",&x,&y))
    {
        if(x==y)
        {
            printf("Yes\n");
        }
        else if(x==1&&y!=1)
        {
            printf("No\n");
        }
        else if(x!=1&&y==1)
        {
            printf("No\n");
        }
        else
        {
            unsigned long long z=gcd(x,y);
            unsigned long long a,b;
            a=x/z;
            b=y/z;
            //cout<<z<<" "<<a<<" "<<b<<endl;
            int aa,bb;
            aa=1;
            bb=1;

            while(1)
            {
                unsigned long long q;
                q=gcd(a,z);
                a=a/q;
                if(a==1)
                {
                    break;
                }
                if(q==1)
                {
                    aa=0;///不行
                    break;
                }
            }
            while(1)
            {
                unsigned long long q;
                q=gcd(b,z);
                b=b/q;
                if(b==1)
                {
                    break;
                }
                if(q==1)
                {
                    bb=0;///不行
                    break;
                }
            }
            if(aa&&bb)
            {
                printf("Yes\n");
            }
            else printf("No\n");
        }
    }
    return 0;
}



Problem H: 玩具

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 718   Solved: 132

Description

商店有 n 个玩具,第 i 个玩具有价格 a[i] 和快乐值 b[i] 。有一天,小王来到商店想买一些玩具,商店老板告诉他,如果他买的所有玩具的位置是连续的,那么老板答应小王购买的所有玩具中某一个可以免费。小王接受老板的提议,他现在有零花钱 k 可以用来买玩具,那么他能获得的最大的快乐值是多少。

Input

第一行给测试总数 T(T <= 100) ,接下来有 T 组测试数据。
每组测试数据第一行有两个数字 n(1 <= n <= 5000) k(0 <= k <= 1000000000)
第二行有 n 个数字,第 i 个数字表示第 i 个玩具的价格 a[i](1 <= a[i] <= 1000000)
第三行有 n 个数字,第 i 个数字表示第 i 个玩具的快乐值 b[i](1 <= b[i] <= 1000000)

Output

每组测试输出小王能获得的最大快乐值。

Sample Input

3
5 14
1 2 3 4 5
5 4 3 2 1
3 1
100 1000 10000
100 1000 10000
1 0
1000000
1000000

Sample Output

15
10000
1000000
题解:前缀和,RMQ,取尺法

当读完这个题的时候想到的是0,1背包的变形,但是包太大了,就不在想了。

后来用的线段树的查询,但是超时了,后来补题的时候想到了前i个数的和,那么s[i]-s[j]及时区间i~j的和了,在用RMQ求区间最大值,此时还是用的n^2的区间判断还是超时了。最后用的取尺法来确定一个区间,因为如果大区间合法的话,那么小区间就不用判断了,这样会节省时间。但是在开始的时候把自己RMQ的区间和前缀和的区间弄混了,卡了好久。

#include <bits/stdc++.h>

using namespace std;

int a[5005],b[5005];
int p[5005],happy[5005];
int M[5005*4];
void build(int node,int b,int e,int M[],int a[])
{
    if(b==e)M[node]=a[b];
    else
    {
        build(2*node,b,(b+e)/2,M,a);
        build(2*node+1,(b+e)/2+1,e,M,a);
        if(M[node*2]>=M[2*node+1])M[node]=M[2*node];
        else M[node]=M[2*node+1];
    }
}
int query(int node,int b,int e,int M[],int i,int j)
{
    int p1,p2;
    if(i>e||j<b)return 0;
    if(b>=i&&e<=j)return M[node];
    p1=query(2*node,b,(b+e)/2,M,i,j);
    p2=query(2*node+1,(b+e)/2+1,e,M,i,j);
    if(p1==0)return p2;
    if(p2==0)return p1;
    if(p1>=p2)return p1;
    return p2;
}
int main()
{
    int t,n,K;
    scanf("%d",&t);
    while(t--)
    {
        int mx=0;
        scanf("%d%d",&n,&K);
        p[0]=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            p[i]=p[i-1]+a[i];
        }
        build(1,1,n,M,a);
        happy[0]=0;
        for(int j=1; j<=n; j++)
        {
            scanf("%d",&b[j]);
            happy[j]=happy[j-1]+b[j];
        }
        int l,r;
        l=1;///不能设为0,因为我的rmq查询的区间最大值是从l->r的全部值,
        ///而我的p和happy所包含的p[r]-p[l]是从l+1->r的值
        r=1;
        while(r<=n)
        {
            if((p[r]-p[l]+a[l]-query(1,1,n,M,l,r))<=K)
            {
                //cout<<l<<" "<<r<<" "<<query(1,1,n,M,l,r)<<endl;
                mx=max(mx,happy[r]-happy[l]+b[l]);
                r++;
            }
            else
            {
                while(l<r&&(p[r]-p[l]+a[l]-query(1,1,n,M,l,r))>K)
                {
                    //cout<<l<<" "<<r<<" "<<query(1,1,n,M,l,r)<<endl;
                    l++;
                    //mx=max(mx,happy[r]-happy[l]);
                }
                if((p[r]-p[l]+a[l]-query(1,1,n,M,l,r))<=K)mx=max(mx,happy[r]-happy[l]+b[l]);
                if(r==n)break;
            }
        }
        printf("%d\n",mx);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值