2024年寒假开学赛题解

题目知识点难度/10
组合数(易)签到题1
最高海拔签到题/前缀和2
连续自然数数学/前缀和3
这题主要考察了找规律递推4
这题主要考察了画画贪心 思维4
组合数(难)数学 + 预处理5
这题主要考察了图的遍历DFS&BFS6
昨夕是何天模拟6
修路并查集6
倍数倍数的特点6
算两次质因数分解7
或与异或位运算 思维8
这题主要考察了DPDP8

combinatorial number(easy)

本场第一签到,根据公式直接算就行了,注意开long long

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

typedef long long LL;

const int N = 100010, mod = 1e9 + 7;

void solve()
{
	int a, b;
	cin >> a >> b;
	
	LL ans1 = 1, ans2 = 1;
	for (int i = 1, j = a; i <= b; i ++, j --)
	{
		ans1 *= j;
		ans2 *= i;
	}
	cout << ans1/ ans2 << endl;
}

int main()
{
    int q;
    cin >> q;
    
    while (q --) solve();
    
    return 0;
}

combinatorial number(normal)

由于 ( a + b ) % m o d = ( a % m o d + b % m o d ) % m o d (a+b)\%mod = (a\%mod + b \% mod)\%mod (a+b)%mod=(a%mod+b%mod)%mod,根据递推公式 C n m = C n − 1 m − 1 + C n − 1 m C^m_n=C^{m-1}_{n-1}+C_{n-1}^m Cnm=Cn1m1+Cn1m,可以求出所有的答案,每次询问时输出预处理出来的答案即可

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2010, mod = 1e9 + 7;
int c[N][N];
void init()
{
	for (int i = 0; i < N; i ++ )
		for (int j = 0; j <= i; j ++ )
			if (!j) c[i][j] = 1;
			else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
 
int main()
{
	init();
	
	int n;
	cin >> n;
	
	while (n --)
	{
		int a, b;
		cin >> a >> b;
		cout << c[a][b] << endl;
	}
	
	return 0;
}

大家去学一下逆元,也可以用下面的方法做

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long 
const int MAX=1e5+10;
const ll mod=1e9+7;
int n, m;
int fact[MAX], infact[MAX];
int quick_power(int a,int b)
{
    int ans = 1;
    while(b)
    {
        if(b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}
void init()
{
    fact[0] = infact[0] = 1;
    for(int i = 1 ; i < MAX ; i ++)
    {
        fact[i] = fact[i-1] * i % mod;
        infact[i] = infact[i-1] * quick_power(i,mod-2) % mod;
    }
}
void solve()
{
    cin >> n >> m;
    cout << (fact[n]%mod*infact[m]%mod*infact[n-m]%mod)%mod << endl; 
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int _;
    cin >> _;
    //_ = 1;
    init();  
    while(_--) solve();
    return 0;
}

这题主要考察了画画

这种题可以多观察一下样例

可以贪心地先把一行填满,每填一个方块可贡献2条需要的对角线(不重复的),剩下的只能填一个,贡献一条对角线了

void solve()
{
	int n,m;
	cin >> n >> m;
	n = n + max(0,n-2);
	
	if(m <= 2*n){
		if(m&1) cout << (m >> 1) + 1 << endl;
		else cout << (m >> 1) << endl;
	}else {
		cout << n + (m - 2 * n) << endl;
	}
	
}

这题主要考察了DP

#include<bits/stdc++.h>
using namespace std;
int n, m;
const int N = 510;
double dp[N][N];
void solve()
{
	cin >> n >> m;
    //dp[i][j]表示前i个人用了j个仙贝的好感度,k为枚举第i个人获得的仙贝数
	for(int i = 1 ; i <= n ; i++)
		for(int j = 1 ; j <= m ; j++)
			for(int k = 1 ; k <= j ; k++)
				dp[i][j] = max(dp[i][j],dp[i-1][j-k] + k*1.0/(m*1.0-(j-k)*1.0));
}
int main()
{
	int _;
	_ = 1;
	while(_--) solve();
	printf("%.6f",dp[n][m]);
}

这题主要考察了图的遍历

跑一边dfs和bfs的板子就行了,但要注意题目要求,如果有很个节点可以遍历,先遍历序号小的。

所有用set存边或者用vector存,然后排序

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 +  100;
set<int> e[N];
int n, m;
int vis[N];
queue<int> q;
void dfs(int u)
{
	if(vis[u]) return;
	vis[u] = 1 ;
	cout << u << " ";
	for(auto v : e[u]) dfs(v);
}
void bfs()
{
	q.push(1);
	while(q.size())
	{
		int u = q.front(); q.pop();
		if(vis[u]) continue;
		vis[u] = 1;
		cout << u << " ";
		for(int v : e[u]) q.push(v);
	}
}
int main()
{

	cin >> n >> m;
	for(int i = 1 ; i <= m ; i ++) 
	{
		int u, v;
		cin >> u >> v ;
		e[u].insert(v);
	}
	dfs(1);
	cout << endl;
	memset(vis , 0 , sizeof vis);
	bfs();
	return 0;
}

这题主要考察了找规律

题目肯定是骗人的,这哪儿来的规律,和爬楼梯类似,第i阶只能由第i-1和i-阶爬到,直接递推就好了,注意开long long

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
long long f[N];
int a[N];
void solve(){
	//这里放自己程序的主函数
	//自己程序的其他函数,直接写在其他地方就行了
  memset(f,0,sizeof f);
  int n;
  scanf("%d",&n);
  for(int i = 0 ; i < n ; i ++) scanf("%d",&a[i]);
  f[0] = 0 , f[1] = a[0];
  for(int i = 2 ; i <= n ; i ++)
    f[i] = min(f[i-1] + (long long)a[i-1],f[i-2]+(long long)a[i-2]);
  printf("%lld",f[n]);
}

int main(void)
{
    solve();
    return 0;
}

我就站在你眼前,你看我有几分像从前

这题是第三次考核题目,但出题的时候发现还是没有一个人补体,所有出出来让大家体会一下没补题的后悔

正解是质因数分解,但是我们给的程序直接取合适的模数也可以

#include <bits/stdc++.h>
#define ll long long
#define N 100005
int f[N],p[N],nu1[N],nu2[N];
int num1=0,num2=0;
int ma=0;
using namespace std;
int num=0;
void init_p()
{
    f[1]=1;
    num=0;
    for(int i=2;i<=N;i++){
        if(f[N]==0){
            p[++num]=i;
        }
        for(int j=1;j<=num;j++){
            if(i*p[j]<N) f[i*p[j]]=1;
            if(i%p[j]==0||i*p[j]>N) break;
        }
    }
}
int main()
{
    init_p();
    int m;
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        int op,x;
        scanf("%d%d",&op,&x);
        if(x<0){
            num1++;
            x=-1*x;
        }
        ma=max(ma,x);
        if(op==1){
            for(int i=1;p[i]<=x;i++){
                if(f[x]==0){
                    nu1[x]++;
                    break;
                }
                while(1){
                    if(x%p[i]==0){
                        nu1[p[i]]++;
                        x/=p[i];
                    }
                    else break;
                }
            }
        }
        else {
            for(int i=1;p[i]<=x;i++){
                if(f[x]==0){
                    nu1[x]--;
                    break;
                }
                while(1){
                    if(x%p[i]==0){
                        nu1[p[i]]--;
                        x/=p[i];
                    }
                    else break;
                }
            }
        }
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        int op,x;
        scanf("%d%d",&op,&x);
        if(x<0){
            num2++;
            x=-1*x;
        }
        ma=max(ma,x);
        if(op==1){
            for(int i=1;p[i]<=x;i++){
                if(f[x]==0){
                    nu2[x]++;
                    break;
                }
                while(1){
                    if(x%p[i]==0){
                        nu2[p[i]]++;
                        x/=p[i];
                    }
                    else break;
                }
            }
        }
        else {
            for(int i=1;p[i]<=x;i++){
                if(f[x]==0){
                    nu2[x]--;
                    break;
                }
                while(1){
                    if(x%p[i]==0){
                        nu2[p[i]]--;
                        x/=p[i];
                    }
                    else break;
                }
            }
        }
    }
    if(num1%2!=num2%2){
        printf("NO");
        return 0;
    }
    for(int i=1;p[i]<=ma;i++){
        if(nu1[p[i]]!=nu2[p[i]]){
            printf("NO");
            return 0;
        }
    }
    printf("YES");
    return 0;
}

修路

考察并查集 如果两个村庄要修路,就合并,每次合并之前查询

#include <bits/stdc++.h>
#define ll long long
#define N 1000005
using namespace std;
int p[N],r[N];
int find(int x)
{
	if(x==p[x]) return p[x];
	else {
		p[x]=find(p[x]);
		return p[x];
	}
}
void join(int x,int y)
{
	int rx=find(x),ry=find(y);
	if(r[rx]<r[ry]) p[rx]=ry;
	else {
		p[ry]=rx;
		if(r[rx]==r[ry]) r[rx]++;
	}
	
}
void init(int n)
{
	for(int i=1;i<=n;i++){
		p[i]=i;
		r[i]=1;
	}
}

int n,m; 
void slove()
{
	scanf("%d%d",&n,&m);
	init(n);
	for(int i=1;i<=m;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		if(find(x)==find(y)){
			printf("No\n");
		}
		else {
			join(x,y);
			printf("Yes\n");
		}
	}
}
int main()
{
	ll t;
	t=1;
	while(t--){
		slove();
	}
	return 0;
 }

倍数

大家要去了解一下怎么判断这些数的倍数

#include <bits/stdc++.h>
#define ll long long
using namespace std;
string s;
int len;
int num[10];
ll get_sum()
{
	ll ret=0;
	for(int i=0;i<len;i++){
		ret+=(s[i]-'0');
	}
	return ret;
}
ll get_he(int x)
{
	ll ret=0;
	for(int i=x;i>=1;i--){
		ret=ret*10+(s[len-i]-'0');
	}
	return ret;
}
int main() 
{
	int q;
	scanf("%d",&q);
	while(q--){
		cin>>s;
		len=s.length();
		ll sum=get_sum();
		if((s[len-1]-'0')%2==0) {
			num[2]++;
			if(sum%3==0) num[6]++;
		}
		if(sum%3==0) num[3]++;
		if(len>=2){
			int x=get_he(2);
			if(x%4==0) num[4]++;
		}
		else {
			int x=get_he(1);
			if(x%4==0) num[4]++;
		} 
		if(s[len-1]=='0'||s[len-1]=='5'){
			if(s!="0") num[5]++;
		}
		if(len>=3){
			int x=get_he(3);
			if(x%8==0) num[8]++; 
		}
		else if(len==2){
			int x=get_he(2);
			if(x%8==0) num[8]++;
		}
		else {
			int x=get_he(1);
			if(x%8==0) num[8]++;
		}
		if(sum%9==0) num[9]++;
	}
	for(int i=2;i<=9;i++){
		if(i==7) continue;
		printf("%d ",num[i]);
	}
}

或与异或

#include <bitsdc++.h>
#define ll long long
using namespace std;
int q;
ll x,y,z;
ll a,b;
int get_ans()
{
	ll p=1;
	do{
		ll xx=x%2,yy=y%2,zz=z%2;
		x/=2;y/=2;z/=2;
		if(xx==0&&yy==1) return 0;
		if(zz==0){
			if(xx!=yy) return 0;
			else {
				if(xx==1){
					a+=p;
					b+=p;
				}
			}
		}
		else {
			if(xx==0||yy==1) return 0;
			else {
				a+=p;
			}
		}
		p*=2;
	}while(x||y||z);
	return 1;
}
int main()
{
	scanf("%d",&q);
	while(q--){
		scanf("%lld %lld %lld",&x,&y,&z);
		a=0,b=0;
		if(get_ans()){
			printf("%lld %lld\n",a,b);
		}
		else printf("-1 -1\n");
	}
	return 0;
}
#include <bitsdc++.h>
#define ll long long
using namespace std;
int q;
ll x,y,z;
ll a,b;
int get_ans()
{
	ll p=1;
	do{
		ll xx=x%2,yy=y%2,zz=z%2;
		x/=2;y/=2;z/=2;
		if(zz==0){
			if(xx!=yy) return 0;
			else {
				if(xx==1){
					a+=p;
					b+=p;
				}
			}
		}
		else {
			if(xx==0||yy==1) return 0;
			else {
				a+=p;
			}
		}
		p*=2;
	}while(x||y||z);
	return 1;
}
int main()
{
	scanf("%d",&q);
	while(q--){
		scanf("%lld %lld %lld",&x,&y,&z);
		if((x^y)==z&&(x|y)==x&&(x&y)==y) printf("%lld %lld\n",x,y);
		else printf("-1 -1\n");
	}
	return 0;
}

前夕是何天

按照题意,计算日期即可

这里有一份把日历存下来,每次询问直接访问的代码

#include <bits/stdc++.h>
using namespace std;
string data[400005];
map <string,int> mp;
int num=0;
string int_to_str(int x,int len)
{
	string ret="";
	for(int i=1;i<=len;i++){
		ret=(char)(x%10+'0')+ret;
		x/=10;
	}
	return ret;
}
void get_data()
{
	int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
	for(int y=2000;y<=3000;y++){
		if((y%4==0&&y%100!=0)||(y%400==0)) day[2]=29;
		else day[2]=28;
		string year=int_to_str(y,4)+'-';
		for(int m=1;m<=12;m++){
			string month=int_to_str(m,2)+'-';
			for(int d=1;d<=day[m];d++){
				string time=year+month+int_to_str(d,2);
				data[++num]=time;
				mp[time]=num;
			}
		}
	}
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	get_data();
	int q;
	string t;
	int k;
	cin>>q;
	while(q--){
		cin>>t>>k;
		int id=mp[t];
		cout<<data[id-k]<<'\n';
	}
	return 0;
}

最高海拔

应该算是本场第二签,前缀和求出来然后找到最大值,输出这个点就好了

#include <stdio.h>
#define ll long long
int main()
{
	ll ma=0,ip=0,sum=0;
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int x;
		scanf("%d",&x);
		sum+=x;
		if(sum>ma){
			ma=sum;
			ip=i;
		}
	}
	printf("%d %d",ip,ma);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值