2017 CCPC 秦皇岛

A:Balloon Robot

题意:有n个参赛人员,有m个座位围成一个圆,n个人员有固定的座位。比赛开始后,如果参赛人员在a时间做出一道题,气球在t时间送到,那么他就会有t-a的不高兴度。现在有一个送气球的机器人,每一个单位时间,它会顺时针移动一个位置,并送气球给相应位置的人,有p个做出问题,然后问它比赛开始的时候它的初始位置在哪,总不高兴度最少。

n,mandp(1<n105),(nm109),(1p105)

分析:开始的时候可以处理出一个从一个位置出发。然后暴力位置是肯定不行的,会T;
我们就处理从m出发。那么对于位置i,机器人到达位置i的时间是m*k+i,那么不开心度为(m*k+i-t)%m=(i-t)%i;对于任何一个起点j,不开心度为(i+j-t)%m
那么处理完之后可以得到每一个问题的不高兴度。把不高兴度从小到大排序。然后从后往前遍历,然后判读一下最小值就行了。
因为有些位置肯定是不行的。比如m = 10,happy[p]=8,那么如果位置加一,happy[1..p-1]都会加1,happy[p]也会加1,那么总的不开心度肯定是增加的。之后最后的happy[p]=0才有可能会减少。

#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
const int maxn = 1e5+10;
ll pos[maxn],h[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        mem(pos,0);mem(h,0);
        ll n,m,p;
        scanf("%lld %lld %lld",&n,&m,&p);
        for(int i=1;i<=n;i++) scanf("%lld",&pos[i]);
        ll ans=0;
        for(int i=0;i<p;i++)
        {
            ll x,t;
            scanf("%lld %lld",&x,&t);
            t=t%m;
            h[i]=(pos[x]-t+m)%m;
            ans+=h[i];
        }
        sort(h,h+p);
        ll tt=0,total=ans;
        for(int i=p-1;i>=0;i--)
        {
            int g=i,num=0;
            while(h[g]==h[i]&&g>=0) {g--;num++;}
            int k=m-h[i];
            ll tmp = k*(p-num);
            tmp=ans+tmp-h[i]*num-tt;
            total=min(tmp,total);
            tt+=m*num;
            i=g+1;
        }
        printf("%lld\n",total);
    }
}

C:Crusaders Quest
这个题很像简化版的zuma。直接放代码

using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn = 20;
char s[maxn];
int dp[maxn][maxn];
struct node
{
    int num;
    char c;
}a[15];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        mem(dp,0);mem(a,0);
        scanf("%s",s);
        a[1].c=s[0];a[1].num=1;
        int now=1,ans=0;
        for(int i=1;i<9;i++)
        {
            if(s[i]==a[now].c)
            {
                a[now].num++;
            }
            else {
                a[++now].c=s[i];
                a[now].num=1;
            }
        }
        for(int len=1;len<=now;len++)
        {
            for(int i=1;i+len-1<=now;i++)
            {
                int j=i+len-1;
                if(i==j) {if(a[i].num==3) dp[i][j]=1;continue;}
                if(a[i].c==a[j].c)
                {
                    if(a[i].num+a[j].num==3)
                    dp[i][j]=max(dp[i][j],dp[i+1][j-1]+1);
                    else {
                        for(int k=i+2;k+1<j;k++){
                            if(a[k].c==a[i].c)
                            dp[i][j]=max(dp[i][j],dp[i+1][k-1]+dp[k+1][j-1]+1);
                        }
                    }
                }
                for(int k=i;k<j;k++)
                dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]);
            }
        }
        printf("%d\n",dp[1][now]);
    }
    return 0;
}

E:String of CCPC

题意:有一个字符串,里面只有C,P两种字符,如果出现了一个CCPC,就算一个贡献,然后可以插入一个C或者P,问价值最大为多少

分析:插入的话只用判断CCP,CCC,CPC这三种情况就行了。同时还要注意不能破坏之前已经存在的CCPC

using namespace std;
const int maxn = 2e5+10;
char s[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        scanf("%s",s);
        int flag=0,ans=0;
        for(int i=0;i<n;i++)
        {
            if(s[i]=='C'&&i+3<n)
            {
                if(s[i+1]=='C'&&s[i+2]=='P'&&s[i+3]=='C'){
                    ans++;
                    continue;
                }
            }
            if(s[i]=='C'&&i+2<n&&!flag)
            {
                if(s[i+1]=='P'&&s[i+2]=='C')
                {
                    if(i>0&&s[i-1]=='C') continue;
                    flag=1;
                    ans++;
                }
                else if(s[i+1]=='C'&&s[i+2]=='P')
                {
                    if(i+3<n&&s[i+3]=='C') continue;
                    flag=1;
                    ans++;
                }
                else if(s[i+1]=='C'&&s[i+2]=='C')
                {
                    if(i+4<n&&s[i+3]=='P'&&s[i+4]=='C')
                        continue;
                    else {
                        flag=1;
                        ans++;
                    }
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

G:Numbers

题意:一个数n,然后把它分成m个数,a1,a2,a3…am, m1ai=n
问a1ORa2ORa3ORa4…ORam最小值是多少。

分析:二进制分析,从高位往低位上看,看那一位上能不能一定是1.
然后数比较大,用java大数

import java.math.BigInteger;
import java.util.Scanner;

public class Main{
    static BigInteger[] pre = new BigInteger[5005];
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int t;
        BigInteger n,m,x,sum,k,y;

        pre[0] = new BigInteger("1");
        x = new BigInteger("2");
        y = new BigInteger("0");
        for(int i=1;i<5005;i++)
            pre[i]=pre[i-1].multiply(x);
        t = in.nextInt();
        for(int ca=0;ca<t;ca++)
        {
            n = in.nextBigInteger();
            m = in.nextBigInteger();
            sum = n;
            BigInteger ans = y;
            k = n.divide(m);
            if(n.compareTo(k.multiply(m))==0) {
                System.out.println(k);
                continue;
            }
            BigInteger temp = n;
            int tol = 0;
            //System.out.println(temp);
            while(temp.compareTo(y)>0)
            {
                temp = temp.divide(x);tol++;
            }
            while(sum.compareTo(y)>0)
            {
                if(sum.compareTo(m)<=0) {
                    ans = ans.add(pre[0]);
                    break;
                }
                for(;tol>=0;tol--)
                {
                    if(sum.compareTo(m.multiply(pre[tol-1]))>0)
                    {
                        if(sum.compareTo(m.multiply(pre[tol]).subtract(m))<=0) {
                            tol = tol - 1;
                            sum = sum.subtract(m.multiply(pre[tol]));
                        }
                        else {
                            BigInteger tt = sum.divide(pre[tol]);
                            sum = sum.subtract(tt.multiply(pre[tol]));
                        }
                        break;
                    }
                }
                ans = ans.add(pre[tol]);
            }
            System.out.println(ans);
        }

    }

}

L:One-Dimensional Maze
分析:签到题,左右跑一下就行了

M:Safest Buildings

题意:二维平面,开始有一个以原点为圆心的半径为R的安全圆,然后,会在这个安全圆从随机出现半径为r的次安全圆(次安全圆完全包含在安全圆中),如果在次安全圆中,则安全。然后给你一些建筑物的坐标,问这些建筑物中安全概率最大的是哪些

分析:

如果r很大的时候
2*r>=R 那么以原点为圆心,半径为(2*r-R)的圆内,概率都是1
如果r很小的时候
2*r

using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn = 100+10;
struct node
{
    int id;
    int t;
}a[maxn];
bool cmp(node a1,node a2)
{
    return a1.t<a2.t;
}
bool cmp2(node a1,node a2)
{
    return a1.id<a2.id;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        mem(a,0);
        int n,R,r;
        scanf("%d %d %d",&n,&R,&r);
        for(int i=1;i<=n;i++){
            int x,y;
            scanf("%d %d",&x,&y);
            a[i].t=x*x+y*y;a[i].id=i;
        }
        sort(a+1,a+n+1,cmp);
        int lim = R*R;
        if(a[1].t>lim)
        {
            printf("0\n\n");continue;
        }
        int ansr = 0;
        if(2*r>=R) ansr = 2*r-R;
        else ansr = R-2*r;
        int temp = ansr*ansr;
        int i=1;
        for(;i<=n;i++)
        {
            if(a[i].t>temp) break;
        }
        if(i-1>0){
            printf("%d\n",i-1);
            sort(a+1,a+i,cmp2);
            for(int j=1;j<=i-1;j++)
            {
                if(j>1) printf(" ");
                printf("%d",a[j].id);
            }
            printf("\n"); continue;
        }
        int k=2;
        for(;k<=n;k++)
        {
            if(a[k].t>a[1].t)
                 break;
        }
        printf("%d\n",k-1);sort(a+1,a+k,cmp2);
        for(int j=1;j<=k-1;j++)
        {
            if(j>1) printf(" ");
            printf("%d",a[j].id);
        }
        printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值