【题目记录】——2021中国大学生程序设计竞赛(CCPC)- 网络选拔赛

本文介绍了四道程序设计竞赛题目,包括1001CutTheWire的电线剪除策略、1006powersum的数字表示、1009CommandSequence的机器人路径模拟以及1011ShootingBricks的射击砖块动态规划解法。通过解析思路和AC代码,展示了如何解决这些算法问题。
摘要由CSDN通过智能技术生成

文章目录

  • 1001 Cut The Wire 思维
  • 1006 power sum 思维
  • 1009 Command Sequence 模拟+思维
  • 1011 Shooting Bricks DP

题目集地址 2021中国大学生程序设计竞赛(CCPC)- 网络选拔赛
题目集原地址 2021中国大学生程序设计竞赛(CCPC)- 网络选拔赛
这次题目集做了三道简单题1001,1006,1009

1001 Cut The Wire 思维

题目地址1001 Cut The Wire
题意:一条路上从标号为1的路灯开始,最大值无上限,路灯与路灯之间有电线,电线连接的规则是:
如果路灯标号x为偶数,则x到 x 2 \frac{x}{2} 2x之间有一条电线。
如果路灯标号x为奇数,则x到3x+1之间有一条电线。
给出你一个x,表示你站在编号为x与x+1的路灯之间。问你最多剪掉多少根电线。
思路:根据数学规律找到左右边界再计算即可。
AC代码:

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;

void solve()
{
    int n;
    int result=0;
    int yu;
    scanf("%d",&n);
    int temp=n;
    result+=((temp+1)/2);
    yu=n%3;
    if(yu==1)
        temp=(n+2)/3;
    else if(yu==2)
    {
        temp=(n+1)/3;
    }
    else
    {
        temp=n/3;
    }
    if(n&1)
        n++;
    if(temp&1)
    {
        result+=((n-temp+1)/2);
    }
    else
    {
        result+=((n-temp)/2);
    }
    printf("%d\n",result);
}

int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    int T;
    scanf("%d\n",&T);
    while(T--)
    {
        solve();
    }
    return 0;
}

1006 power sum 思维

题目地址1006 power sum
题目大意:给一个数字n,整数k和一个数组a[i], a i ∈ − 1 , 1 a_i\in{-1,1} ai1,1,数组a[i]的长度不超过K+2,满足 ∑ i = 1 k a i ∗ i 2 = n \sum^{k}_{i=1}{a_i*i^2}=n i=1kaii2=n
输出一个01字符串,0表示第i个数 x 2 x^2 x2*(-1),1表示第i个数 x 2 x^2 x2*1,
思路:可以看到相邻两个数的平方的差值是按照连续奇数序列上升的,也就是说大于4的k值后面每一个1001都会是一个4,这样只需要先找出前面4项的表示,后面只需要看有几个4就有几个1001即可。
AC代码:

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;

int main()
{
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	string a[4]={"","1","0001","01"};
    int b[4]={0,1,4,2};
    int t;
    scanf("%d",&t);
    while(t--)
    {
        string ans;
        int x,num = 0;
        scanf("%d",&x);
        num += b[x%4];
        ans=a[x%4];
        while(x >= 4)
        {
            x-=4;
            num+=4;
            ans+="1001";
        }
        cout << num << endl;
        cout << ans << endl;
    }
    return 0;
}

1009 Command Sequence 模拟+思维

题目地址:1009 Command Sequence
题目大意:给定一个命令序列,有四种命令,上下左右移动,问给出的序列有多少个连续子序列能够让机器人回到原点
思路:一开始觉得是一个动态规划之类的。结果发现只需要模拟就好了,设初始坐标为0,0,每走到一个坐标就让坐标值的访问次数加一,最后所有坐标值减一的值到1类和,最后求所有坐标值得累和就可以了。
AC代码:

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <time.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int maxn=2e6+10;
ll t,n,x,y;
char str[maxn];
ll sum(ll t) {
    return t*(t-1)/2;
}
ll Hash() {
    return x*1000000+y;
}
int main() {
//    freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
    scanf("%lld",&t);
    while(t--) {
        unordered_map<ll,ll>U;
        U[0]=1;
        ll ans=0;
        x=0,y=0;
        scanf("%lld",&n);
        getchar();
        scanf("%s",str+1);
        for(int i=1; i<=n; i++) {
            switch(str[i]) {
            case 'U':
                y++;
                break;
            case 'D':
                y--;
                break;
            case 'L':
                x--;
                break;
            case 'R':
                x++;
                break;
            }
            U[Hash()]++;
        }
        unordered_map<ll,ll>::iterator p;
        for(p=U.begin(); p!=U.end(); p++)
            ans+=sum(p->second);
        printf("%lld\n",ans);
    }
    return 0;
}

1011 Shooting Bricks DP

题目地址1011 Shooting Bricks
此题目与洛谷1174撞题,题意参考洛谷即可。
思路:dp


#include <bits/stdc++.h>
//#include <iostream>
//#include <cstdio>
//#include <cstring>
//#include <algorithm>
//#include <vector>
//#include <map>
//#include <stack>
//#include <queue>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int N = 205;
int n, m, k;
int sy[N][N],sn[N][N];//sy[i][j],sn[i][j]第i列消耗j颗子弹得到的分数,y表示最后一颗子弹打在第i列上,n表示没有打在第i列上
int s[N][N],c[N][N];//s表示每个位置的砖块的分数,c表示每个位置是否会得到一个子弹
int fn[N][N],fy[N][N];//fn[i][j],fy[i][j]表示前i列一共消耗j颗子弹得到的分数,最后一颗是否打在第i列上,n表示没有打在第i列,y表示打在第i列
void init()
{
    memset(sy,0,sizeof(sy));
    memset(sn,0,sizeof(sn));
    memset(fy,0,sizeof(fy));
    memset(fn,0,sizeof(fn));
    memset(c,0,sizeof(c));
}
void solve()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i = 1;i <= n;i ++)
    {
        for(int j = 1;j <= m;j++)
        {
            char ch;
            scanf("%d %c",&s[i][j],&ch);
            if(ch=='Y')
            {
                c[i][j] = 1;
            }
        }
    }
    for(int i = 1;i <= m;i++)
    {
        int cnt = 0;
        for(int j = n;j >= 1;j--)
        {
            if(c[j][i])
            {
                sn[i][cnt] += s[j][i];
            }
            else
            {
                cnt++;
                sn[i][cnt] = sn[i][cnt-1] + s[j][i];
                sy[i][cnt] = sn[i][cnt-1] + s[j][i];
            }
        }
    }

    for(int x = 1; x <= m; x++)//当前列
    {
        for(int y = 0; y <= k;y++)//总共y个子弹
        {
            for(int z = 0;z <= n&&z <= y;z++)//当前列用了z个子弹
            {
                fn[x][y]=max(fn[x][y],fn[x-1][y-z]+sn[x][z]);
                if(z!=0) fy[x][y]=max(fy[x][y],fn[x-1][y-z]+sy[x][z]);
                if(y-z>0) fy[x][y]=max(fy[x][y],fy[x-1][y-z]+sn[x][z]);
            }
        }
    }
    cout<<fy[m][k]<< endl;
    init();
}

int main()
{
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
//	int t = 1;
	int t;
	scanf("%d",&t);
	while(t--)
	{
		solve();
	}
    return 0;
}
  • 1
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值