CodeCraft-21 and Codeforces Round #711 (Div. 2)题解

A GCD Sum

【题目描述】

The gcdSum of a positive integer is the gcd of that integer with its sum of digits. Formally, gcdSum(x)=gcd(x, sum of digits of x) for a positive integer x. gcd(a,b) denotes the greatest common divisor of a and b — the largest integer d such that both integers a and b are divisible by d.

For example: gcdSum(762)=gcd(762,7+6+2)=gcd(762,15)=3.

Given an integer n, find the smallest integer x≥n such that gcdSum(x)>1.

【Input】

The first line of input contains one integer t (1≤t≤104) — the number of test cases.

Then t lines follow, each containing a single integer n (1≤n≤1018).

All test cases in one test are different.

【Output】

Output t lines, where the i-th line is a single integer containing the answer to the i-th test case.

【Example】

inputCopy
3
11
31
75
outputCopy
12
33
75

【Note】

Let us explain the three test cases in the sample.

Test case 1: n=11:

gcdSum(11)=gcd(11,1+1)=gcd(11, 2)=1.

gcdSum(12)=gcd(12,1+2)=gcd(12, 3)=3.

So the smallest number ≥11 whose gcdSum >1 is 12.

Test case 2: n=31:

gcdSum(31)=gcd(31,3+1)=gcd(31, 4)=1.

gcdSum(32)=gcd(32,3+2)=gcd(32, 5)=1.

gcdSum(33)=gcd(33,3+3)=gcd(33, 6)=3.

So the smallest number ≥31 whose gcdSum >1 is 33.

Test case 3: n=75:

gcdSum(75)=gcd(75,7+5)=gcd(75, 12)=3.

The gcdSum of 75 is already >1. Hence, it is the answer.

【题意理解】

题意就是给你一个n让你求一个比n大的第一个gcdSum(n)的整数,主要就是考察了对于整数的求各位数字的和,然后自己手写个gcd函数,从n向上一直遍历就好了,关键在于看题速度和手速;
还有一点就是要注意开long long,看到样例,你就知道后面的几组测试用例都非常大

【代码展示】

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int x,y;
 
ll gethe(ll n)
{
    ll sum =0;
    while(n)
    {
        sum += n%10;
        n/=10;
    }
    return sum;
}
 
ll gcd(ll a,ll b)
{
    if(a<b)
    {
        swap(a,b);
    }
    return b==0?a:gcd(b,a%b);
}
 
ll gcdsum(ll n)
{
    while(gcd(n,gethe(n))==1)
    {
        n++;
    }
    return n;
}
 
int main()
{
    ll n;
    int t;
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld",&n);
        ll x = gcdsum(n);
 
        printf("%lld\n",x);
    }
    return 0;
}

B. Box Fitting

【题目描述】

You are given n rectangles, each of height 1. Each rectangle’s width is a power of 2 (i. e. it can be represented as 2x for some non-negative integer x).

You are also given a two-dimensional box of width W. Note that W may or may not be a power of 2. Moreover, W is at least as large as the width of the largest rectangle.

You have to find the smallest height of this box, such that it is able to fit all the given rectangles. It is allowed to have some empty space left in this box after fitting all the rectangles.

You cannot rotate the given rectangles to make them fit into the box. Moreover, any two distinct rectangles must not overlap, i. e., any two distinct rectangles must have zero intersection area.

See notes for visual explanation of sample input.

【Input】

The first line of input contains one integer t (1≤t≤5⋅103) — the number of test cases. Each test case consists of two lines.

For each test case:

the first line contains two integers n (1≤n≤105) and W (1≤W≤109);
the second line contains n integers w1,w2,…,wn (1≤wi≤106), where wi is the width of the i-th rectangle. Each wi is a power of 2;
additionally, maxi=1nwi≤W.
The sum of n over all test cases does not exceed 105.

【Output】

Output t integers. The i-th integer should be equal to the answer to the i-th test case — the smallest height of the box.

【Example】

inputCopy
2
5 16
1 2 8 4 8
6 10
2 8 8 2 2 8
outputCopy
2
3

【Note】

For the first test case in the sample input, the following figure shows one way to fit the given five rectangles into the 2D box with minimum height:

In the figure above, the number inside each rectangle is its width. The width of the 2D box is 16 (indicated with arrow below). The minimum height required for the 2D box in this case is 2 (indicated on the left).

In the second test case, you can have a minimum height of three by keeping two blocks (one each of widths eight and two) on each of the three levels.

【题意理解】

这道题目就是说给你很多高度为1、长度不定,的长方形木条,给你一个宽度为w(w一定大于等于所有木条的长度)木框,让你把木条全部放进木框,求木框的最低高度
要用到一个叫优先队列的数据结构,这个数据结构默认是按照大顶堆的方式存储当你把木箱中的每一层剩余空间都放进去(开始默认只放一个w进去,代表开辟第一个空行,用来放置木条,后面空间不够的是时候就在开辟新的一层)放进优先队列里,这个优先队列会自动按照剩余空间的大小排好序,另外还需要把所有的木条按照长度大小从大到小排序,这样每次都能拿最大的木条对应木箱中剩余空间最大的那一层,所有木条放置完后,优先队列的大小就是木箱的层数。nice(终于打完了)

【代码展示】


#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 1000+5;
const int mod = 1e9+7;


int t,n,w;//表示t组测试样例,n块木板,w表示框子的长度

bool cmp(int a,int b)
{
    return a>b;
}

void solve(vector<int> &a)
{
    sort(a.begin(),a.end(),cmp);//按照从大到小的顺序排列,这样就可以保证每次去的值都是最大的
    priority_queue<int> q;//优先队列q,这样默认就是大顶堆
    q.push(w);//第一排是空着的
    for(int i=0;i<n;i++)
    {
        if(q.top() < a[i])//如果最大的这一层放不下a[i],就在开辟一层
        {
            q.push(w-a[i]);
        }
        else//可以放下,就要修改top()这一层的剩余空间,并且重新压回去。优先队列会自动按照剩余空间大小排列
        {
            int temp = q.top() - a[i];
            q.pop();
            q.push(temp);
        }
    }
    cout<<q.size()<<endl;//最后优先队列的大小就是木箱的层数
}
int main()
{
    while(cin>>t)
    {
        while(t--)
        {
            cin>>n>>w;
            vector<int> a(n);
            for(int i=0;i<n;i++)
            {
                cin>>a[i];
            }
            solve(a);
        }
    }
    return 0;
}

C. Planar Reflections

【题目描述】

Gaurang has grown up in a mystical universe. He is faced by n consecutive 2D planes. He shoots a particle of decay age k at the planes.

A particle can pass through a plane directly, however, every plane produces an identical copy of the particle going in the opposite direction with a decay age k−1. If a particle has decay age equal to 1, it will NOT produce a copy.

For example, if there are two planes and a particle is shot with decay age 3 (towards the right), the process is as follows: (here, D(x) refers to a single particle with decay age x)

the first plane produces a D(2) to the left and lets D(3) continue on to the right;
the second plane produces a D(2) to the left and lets D(3) continue on to the right;
the first plane lets D(2) continue on to the left and produces a D(1) to the right;
the second plane lets D(1) continue on to the right (D(1) cannot produce any copies).
In total, the final multiset S of particles is {D(3),D(2),D(2),D(1)}. (See notes for visual explanation of this test case.)

Gaurang is unable to cope up with the complexity of this situation when the number of planes is too large. Help Gaurang find the size of the multiset S, given n and k.

Since the size of the multiset can be very large, you have to output it modulo 109+7.

Note: Particles can go back and forth between the planes without colliding with each other.

【Input】

The first line of the input contains the number of test cases t (1≤t≤100). Then, t lines follow, each containing two integers n and k (1≤n,k≤1000).

Additionally, the sum of n over all test cases will not exceed 1000, and the sum of k over all test cases will not exceed 1000. All test cases in one test are different.

【Output】

Output t integers. The i-th of them should be equal to the answer to the i-th test case.

【Examples】

inputCopy
4
2 3
2 2
3 1
1 3
outputCopy
4
3
1
2
inputCopy
3
1 1
1 500
500 250
outputCopy
1
2
257950823

【Note】

Let us explain the first example with four test cases.

Test case 1: (n=2, k=3) is already explained in the problem statement.

See the below figure of this simulation. Each straight line with a different color represents the path of a different particle. As you can see, there are four distinct particles in the multiset. Note that the vertical spacing between reflected particles is for visual clarity only (as mentioned before, no two distinct particles collide with each other)

Test case 2: (n=2, k=2) is explained as follows:

the first plane produces a D(1) to the left and lets D(2) continue on to the right;
the second plane produces a D(1) to the left and lets D(2) continue on to the right;
the first plane lets D(1) continue on to the left (D(1) cannot produce any copies).
Total size of multiset obtained {D(1),D(1),D(2)} is equal to three.

Test case 3: (n=3, k=1), there are three planes, but decay age is only one. So no new copies are produced while the one particle passes through the planes. Hence, the answer is one.

Test case 4: (n=1, k=3) there is only one plane. The particle produces a new copy to the left. The multiset {D(2),D(3)} is of size two.

【题意理解】

这里附上大佬的链接,我也是想这位大佬学习的,当时打比赛我连b题都没过,下来想大佬学习着补题,如有不足,请参考大佬的博客
题意:
由于这道题可能题意比较难理解,所以这里解释一下。题目中说明初始时有一个衰减年龄为k的粒子,同时在它的前进方向有n的平面,当粒子经过一个平面后,如果粒子的衰减年龄k大于1,那么它就会往相反的方向产生一个衰减年龄为k − 1的粒子。 问这样的一个粒子最终能够产生多少个粒子?
例如对于n = 2 , k = 3 的时候,如下图:
在这里插入图片描述

我们发现这样的一个粒子最后能得到4个粒子。

解题思路
我们还是继续分析这个样例,我们发现,这样拆分之后其实就像是一个状态被分解一样。我们可以定义这样的一个状态:d p [ i ] [ j ] ,它表示运动前方还有i个平面,且衰变年龄为j的粒子所能产生的粒子数量。
那么样例中的d p [ 2 ] [ 3 ] ,它反弹后的粒子状态为d p [ 0 ] [ 2 ](由于反弹,方向改变,所以运动前方剩余平面为n − i n-in−i个),它继续往前的状态为d p [ 1 ] [ 3 ] ,即d p [ 2 ] [ 3 ] = d p [ n − i ] [ 3 − 1 ] + d p [ 2 − 1 ] [ 3 ] 。那么这就显而易见了,答案是d p [ n ] [ k ],到这一步我们最关键的就是将初始状态给找出来,对于衰变年龄为1的粒子,它不过经过多少个平面,所能产生的粒子就是它本身。而对于运动前方没有平面的粒子,是不能分裂的。粒子数量只有它本身。 即初始状态如下:

for(int i=1;i<=n;i++){
    dp[i][1]=1;
}
for(int j=1;j<=k;j++){
    dp[0][j]=1;
}

值得注意的一点就是在处理状态转移的时候,我们为了通过前面状态得到后面状态就必须先推出 j − 1 的 1 ~ n 所有情况,因为我们在 j 的时候会引用到 n − i,这样就会造成错误。
原文链接:https://blog.csdn.net/hzf0701/article/details/115328566

【代码展示】

/**
  *@filename:C
  *@author: pursuit
  *@CSDNBlog:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-03-30 15:37
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1000 + 5;
const int mod = 1e9+7;

int t,n,k;//n个平面,k表示为衰变年龄。
int dp[maxn][maxn];//定义状态:用dp[i][j]表示运动前方还有k个平面,且衰变年龄为j的粒子所能产生的粒子数量。
void solve(){
    memset(dp,0,sizeof(dp));
    //初始状态,对于衰变年龄为1的粒子,它不过经过多少个平面,所能产生的粒子就是它本身。
    for(int i=1;i<=n;i++){
        dp[i][1]=1;
    }
    //对于运动前方没有平面的粒子,是不能分裂的。粒子数量只有它本身。
    for(int j=1;j<=k;j++){
        dp[0][j]=1;
    }
    //为了通过前面状态得到后面状态,所以我们先要推出j的所有情况。
    for(int j=1;j<=k;j++){
        for(int i=1;i<=n;i++){
            dp[i][j]=(dp[i-1][j]+dp[n-i][j-1])%mod;
        }
    }
    cout<<dp[n][k]<<endl;
}
int main() {
    while(cin>>t){
        while(t--){
            cin>>n>>k;
            solve();
        }
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值