2022牛客寒假算法基础集训营1全部题解

Posted quinn18

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2022牛客寒假算法基础集训营1全部题解相关的知识,希望对你有一定的参考价值。

文章目录


比赛链接


A 九小时九个人九扇门 dp

题目链接
题意:
一个数字的数字根是指:将该数字各数位上的数字相加得到一个新的数,直到得到的数字小于 10 10 10 为止.。设置小于 10 10 10 的数字,其数字根就为其本身。
k k k 个人能够打开门上数字为d的一扇数字门,当且仅当这 k k k 个人的腕表数字之和的数字根恰好为 d d d
( 1 < = n < = 1 e 5 , 1 < a i < = 1 e 9 ) (1<=n<=1e5,1<ai<=1e9) (1<=n<=1e5,1<ai<=1e9)

题解:
状态
d p [ i ] [ j ] dp[i][j] dp[i][j] 表示考虑了前 i i i 个数,选择了一些数字使得数字根为 j j j 的方案数

转移方程
不加当前位使得数字根为 j j j 的方案数为上一位继承来
d p [ i ] [ j ] + = d p [ i − 1 ] [ j ] ; dp[i][j] += dp[i - 1][j]; dp[i][j]+=dp[i1][j];
加上当前位使得数字根为 f ( a [ i ] ∗ 10 + j ) f(a[i]*10+j) f(a[i]10+j) 的方案数为上一位继承来
d p [ i ] [ f ( a [ i ] ∗ 10 + j ) ] + = d p [ i − 1 ] [ j ] ; dp[i][f(a[i]*10+j)] += dp[i - 1][j]; dp[i][f(a[i]10+j)]+=dp[i1][j];
当前位的方案数+1
d p [ i ] [ f ( a [ i ] ) ] + + ; dp[i][f(a[i])]++; dp[i][f(a[i])]++;

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+100; 
const int M=998244353;
int t;
int a[N];
int b[N];
int f[10][N];
int fun(int n) 
	if(n<10) return n;
	while(n>=10) 
        int m=0;
        while(n) 
            m+=n%10;
            n/=10;
        
        n=m;
	
	return n;

signed main() 
	t=1;
	while(t--) 
		int n;
		cin>>n;
		for(int i=1; i<=n; i++) 
			cin>>a[i];
			a[i]=fun(a[i]);
			for(int j=0; j<=9; j++) 
				int tmp=fun(a[i]*10+j);
				f[j][i]+=f[j][i-1]%M;
                f[tmp][i]=(f[tmp][i]+f[j][i-1])%M;
			
			f[a[i]][i]++;
		
		for(int i=1; i<=9; i++) 
			cout<<f[i][n]%M<<" ";
		
		cout<<endl;
	
	return 0;

H 牛牛看云 思维

题目链接
题意:

n n n n n n
Σ Σ Σ Σ Σ Σ ∣ a i + a j − 1000 ∣ ∣ai+a j −1000∣ ai+aj1000
i i i=1 j j j= i i i
( 0 < a i < = 1000 , n < = 1000000 ) (0<ai<=1000, n<=1000000) (0<ai<=1000,n<=1000000)

题解:
因为这个 n n n 很打, a i ai ai很小
就从 a i ai ai 入手
记录 a i ai ai 的个数枚举 a i ai ai
直接计算答案
假如 a i = = a j ai==aj ai==aj ans=自己和自己+自己和别人 / 2 /2 /2 (因为 j j j 是从 i i i 开始的 所以 / 2 /2 /2
a i ! = a j ai!=aj ai!=aj ans= c n t [ a i ] ∗ c n t [ a j ] / 2 cnt[ai]*cnt[aj]/2 cnt[ai]cnt[aj]/2

vector<int> g[N];
signed main() 
    ios_base::sync_with_stdio(0), cin.tie(0); cout.tie(0);
    int n;cin>>n;
    for(int i=1; i<=n; i++) 
        int x; 
        cin>>x;
        g[x].push_back(i);
    
    int ans=0;
    int a, b;
    for(int i=0; i<=1000; i++) 
        for(int j=i; j<=1000; j++) 
            int a=g[i].size();
            int b=g[j].size();
            if(i==j) 
                ans+=(a+a*(a-1)/2)*abs(i+i-1000);
             else 
                ans+=a*b*abs(i+j-1000);
            
        
    
    cout<<ans<<endl;
    return 0;

F 中位数切分 思维

题目链接
题意:
给定一个长为 n n n 的数组 a a a 和一个整数 m m m,求最多可以划分成多少段,使得每一段的中位数都大于等于 m m m ( 1 < a i , m < = 1 e 9 , 1 < = n < = 1 e 5 ) (1<ai, m<=1e9, 1<=n<=1e5) (1<ai,m<=1e9,1<=n<=1e5)
题解:
原数组大于等于m的记为1,记录 c n t 1 cnt1 cnt1
小于的记为-1,记录 c n t 2 cnt2 cnt2
当一段的 s u m > = 1 sum>=1 sum>=1 的时候这一段中位数就 > = m >=m >=m
然后就去拿 1 1 1 的去中和 − 1 -1 1, 最大的段数就是先把负数中和了使得 s u m = = 0 sum==0 sum==0 再加上一个 1 1 1,假如 c n t 1 − c n t 2 < = 0 cnt1-cnt2<=0 cnt1cnt2<=0则不存在,不然段数为 c n t 1 − c n t 2 cnt1-cnt2 cnt1cnt2个 。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
const double eps=1e-4;
int n, m;int a[N];
signed main() 
    ios_base::sync_with_stdio(0), cin.tie(0); cout.tie(0);
    int t;
    cin>>t;
    while(t--) 
         cin>>n>>m;
         int p=0;
         for(int i=1; i<=n; i++) 
            cin>>a[i];
            if(a[i]>=m) p++;
         
         if(p-(n-p)>0) cout<<p-(n-p)<<endl;
         else cout<<-1<<endl;
    
    return 0;

I B站与各唱各的 数学

题目链接
题意:
分子为欧拉函数

题解:
打表呜呜呜
最小值是

下一个数是210
就发现是素数的乘积 2 , 2 ∗ 3 , 2 ∗ 3 ∗ 5 2,2*3,2*3*5 2,23,

以上是关于2022牛客寒假算法基础集训营1全部题解的主要内容,如果未能解决你的问题,请参考以下文章

2022牛客寒假算法基础集训营3全部题解

2022牛客寒假算法基础集训营 5 全部题解

2022牛客寒假算法基础集训营 5 全部题解

2022牛客寒假算法基础集训营6 全部题解

2022牛客寒假算法基础集训营6 全部题解

2022牛客寒假算法基础集训营 4 全部题解