当前位置: 首页 > news >正文

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;
}

http://www.mrgr.cn/news/40793.html

相关文章:

  • 10.数据结构与算法-线性表的应用(线性表与有序表的合并)
  • MQ高级:RabbitMQ小细节
  • 期权卖方怎么选择权利金高的品种,期货VIX高低对行情有什么影响
  • python 实现knapsack背包问题算法
  • Egg.js 系列(1):Egg是什么、快速入门、目录结构
  • C++入门(有C语言基础)
  • SpringMVC——REST
  • 车辆重识别(2020NIPS去噪扩散概率模型)论文阅读2024/9/27
  • MySQL表的约束
  • JS+HTML基础
  • 性能微基准测试JMH
  • windows系统控制面板里面卸载软件的时候,出现invalid uninstall control file错误怎么办
  • 初始C语言(五)
  • 基础算法--双指针【概念+图解+题解+解释】
  • Qt界面优化——QSS
  • Nginx基础详解4(location模块、nginx跨域问题的解决、nginx防盗链的设计原理及应用、nginx模块化解剖)
  • 【Python报错已解决】KeyError: ‘key‘
  • 计算机网络:计算机网络概述:网络、互联网与因特网的区别
  • 数据结构-3.8.栈在括号匹配中的应用
  • 数据结构-3.10.队列的应用