栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

2021.9.20 CSP模拟赛总结+题解

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

2021.9.20 CSP模拟赛总结+题解

#  2021.9.20 CSP模拟赛总结+题解

## 凑数2526         

#### 题目描述

```
一个长度为n+m+k,包含n个数字2,m个数字5和k个数字6的序列,最多可能有多少个子序列是2526?

如果一个序列是数组的子序列,当且仅当这个序列可以由数组删去任意个元素,再将数组中的剩余元素按顺序排列而成。
```

#### 输入格式

```
第一行一个整数t,表示测试用例的组数。

接下来t行每行三个整数nm,k表示一组测试用例。
```

#### 输出格式

```
对于每组测试用例输出一行一个整数表示答案。
```

#### 样例输入

```
3
6 7 8
1 2 2
6 0 3
```

#### 样例输出

```
504
0
0
```

#### 数据范围与提示

1<=t<=200000  
 0<=n,m,k<=10000

#### 思路

把n分成2份,即n/2

然后求排列

如下:

```
n*m*n*k
```

##### 注意

n为奇数时其中一个n除完要加1

### CODE

```c++
#include
using namespace std;
long long int n,m,k,tmp,ans,t,bj;
int main()
{
    cin>>t;
    for(int i=1;i<=t;i++)//多组测试数据
    {
        scanf("%lld%lld%lld",&n,&m,&k);
        tmp=n/2;
        n=n-tmp;//加1操作 因为tmp是n/2,那n-tmp就是已经n的一半,加1操作也有了
        ans=n*m*tmp*k;
        cout<     }
}
```

### 总结

这题想思路的时候慢了点

但想到了就挺好做的

#### 注意

一定比赛要检查程序

旁边的一位没检查程序,漏了换行

## 最小乘积              

#### 题目描述

```
给你两个非负的整数L,R,在区间[L,R]中找两个不同的数,使得它们的乘积模2019最小,输出这个结果。
```

#### 输入格式

```
第一行两个整数L,R
```

#### 输出格式

```
一行,表示mod 2019的最小值。
```

#### 输入样例1

```
2020 2040
```

#### 输出样例1

```
2
```

#### 输入样例2

```
4 5
```

#### 输出样例2

```
20
```

#### 数据范围与提示

0<=L<=R<=$10^9$

### 思路

要往2019的倍数去想

只要R-L>=2019那么就一定有2019的倍数,那么2019的倍数乘以任何数都可以被2019整除

那剩下的就暴力就好了

所以这题就变简单了

算出R-L,大于等于2019的话直接输出0,小于2019的话做暴力做法

虽然暴力的时间复杂都还是O($n^2$),但暴力只用处理2019以下的数据

怎么暴力就不说了 ~~懂得都懂~~

### CODE

```c++
#include
using namespace std;
long long int l,r,minn=2020;
int main()
{
    cin>>l>>r;
    if(r-l>=2019)//大于的情况
    {
        cout<<0;
        return 0;
    }
    for(long long  i=l;i<=r;i++)//由于数据较大,相乘要开long long 类型
    {
        for(long long  j=l;j<=r;j++)//暴力
        {
            if(i==j) continue;
            minn=min(i*j%2019,minn);
        }
    }
    cout< }
```

### 总结

这题思路就是倍数,但在coding的时候没有想到i,j要开long long ,所以痛失44分

## 雨水

#### 题目描述

有n座山排成一个圆环,编号为1~n。两座山之间有一个水坝。第i座山和第i+1座山之间的水坝称为第i个水坝。因为山是环形的,第n+1座山也是第1座山。第n+1个水坝也是第1个水坝。如果第i座山降雨量为2Li,则它的降雨量会平均地分到相邻的两座水坝去。假设水坝的水全是由山上的降雨提供。现在给出每一座水坝收到的水量,问每座山的降雨量。n是奇数。

#### 输入格式

第一行一个整数n 接下来第二行有n个整数,表示每座水坝的水量。

#### 输出格式

输出一行,共有n个数,表示每座山的降雨量。

#### 输入样例1

```
3
2 2 4
```

#### 输出样例1

```
4 0 4
```

### 思路

这题是一个二分的思路,mid枚举第一座山的降雨量的一半,通过暴力求出mid是否可行,可行就输出,mid小了则最后的水库1和水库n必有一水库水多了,mid大了着相反,这样求一个单调mid。

### CODE

```c++
#include
using namespace std;
long long int waterku[200000],taxtwaterku[200000],n;
int check(long long int x)//检查mid值是否可行
{
    for(int i=1;i<=n;i++) taxtwaterku[i]=waterku[i];
    taxtwaterku[1]-=x;
    taxtwaterku[n]-=x;
    for(int i=2;i<=n;i++)
    {
        int u=min(taxtwaterku[i],taxtwaterku[i-1]);
        taxtwaterku[i]-=u;
        taxtwaterku[i-1]-=u;
    }
    int flag=1;
    for(int i=1;i<=n;i++)
    {
        if(taxtwaterku[i]>0) flag=0;
    }
    if(flag==1) return 1;
    else if(taxtwaterku[1]>0||taxtwaterku[n]>0) return 2;
    else return 3;
}
int out(long long int x)//输出把mid在枚举一遍
{
    for(int i=1;i<=n;i++) taxtwaterku[i]=waterku[i];
    taxtwaterku[1]-=x;
    taxtwaterku[n]-=x;
    cout<     for(int i=2;i<=n;i++)
    {
        int u=min(taxtwaterku[i],taxtwaterku[i-1]);
        cout<         taxtwaterku[i]-=u;
        taxtwaterku[i-1]-=u;
    }
    exit(0);
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>waterku[i];
    }
    int l=0,r=max(waterku[1],waterku[n]);
    while(l<=r)//二分,这里是l<=r
    {
        long long int mid=(l+r)/2;
        int flag=check(mid);
        if(flag==1)
        {
            out(mid);
        }
        else if(flag==2)
            l=mid+1;
        else
            r=mid;
    }
}
```

### 总结

这题挺简单的,可惜考试是没有想出来。想到了二分,但没有想到mid枚举什么。

## 染色

#### 题目描述

有一棵树,包含n个点,n-1条边,第i条边的两个端点为ui,vi,现在你要对所有的点染色,你一共有K种颜色。染色要求符合以下条件:

- 对两个距离小于等于2的不同顶点,它们必须染成不一样的颜色。

问有多少种染色的方案。输出模$10^9+7$的结果。

#### 输入格式

第一行两个数,表示N和K。 接下来有N-1行,每一行两个整数,表示一条边的两个端点。

#### 输出格式

一个答案。

#### 输入样例1

```
4 3
1 2
2 3
3 4
```

#### 输出样例1

```
6
```

#### 数据范围与提示

1<=n,k<=$10^5$ 1<=$u_i$,$v_i$<=n

### 思路

DFS推导,一个节点的贡献量即为k-爸爸-兄弟,在把贡献相乘即可。

### CODE

```c++
#include
using namespace std;
long long nex[1000000],a[1000000],p[1000000],num[1000000],bj[1000000],ans=1,cn,n,k;
int dfs(int x,int fa,int br)
{
    ans*=k-fa-br;//方案数
    ans%=1000000007;
    bj[x]=1;
    int t=0;
    for(int i=num[x];i;i=nex[i])
    {
        if(bj[a[i]]==1) continue;
        if(fa+1<=2)
        {
            dfs(a[i],fa+1,t);
        }
        else
        {
            dfs(a[i],fa,t);
        }
        t++;
    }
    
}
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n-1;i++)
    {
        int u,v;
        cin>>u>>v;
        cn++;
        a[cn]=u;
        nex[cn]=num[v];
        num[v]=cn;
        cn++;
        a[cn]=v;
        nex[cn]=num[u];
        num[u]=cn;//链式前向星
    }
    dfs(1,0,0);
    cout< }
```

### 总结

这题要仔细思考每个点的贡献,再用排列法求解

## 全局总结

这次题目并不难,只是没有认真思考。

也没有进行结束检查,在考试范低级错误丢分是很严重的问题。

以后考试后30分钟要记得检查。

还要提升自己的思维和代码实践能力。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/296513.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号