A.交换a,b的值
直接输出b,a
void solve()
{
int a,b;
cin>>a>>b;
cout<<b<<" "<<a;
}
B.素数回文数的个数
从11~n遍历一遍找出满足即是回文数又是素数的数
bool isPalindrome(int n)//判断是否是回文数
{
string s = to_string(n);
int i=0,j = s.size()-1;
while(i<j){
if(s[i++]!=s[j--]) return false;
}
return true;
}
bool isPrime(int n)//判断是否是素数
{
if(n==1) return false;
for(int i=2;i<=n/i;i++){
if(n%i==0) return false;
}
return true;
}
void solve()
{
int n;
cin>>n;
int res = 0;
for(int i=11;i<=n;i++){
if(isPalindrome(i) && isPrime(i)) res++;
}
cout<<res;
}
C.机器翻译
利用队列实现,用一个vis数组记录内存中是否有某个单词,如果在不在内存内,查询次数+1,队首元素删除,将刚查询的元素入队,更新vis数组
bool vis[1000+10];//记录内存单词状态
void solve()
{
int n,m;
cin>>n>>m;
queue<int>q;
int res = 0;//查询次数
while(m--){
int e;
cin>>e;
if(!vis[e]){
if(q.size()<n){
q.push(e);
}else{
vis[q.front()] = false;
q.pop();
q.push(e);
}
res++;
vis[e] = true;
}
}
cout<<res;
}
D.素数对
先用素数筛将1~n的素数预处理出来,再遍历一遍预处理出来的素数表prime,相邻两个素数若相差2则输出
int prime[10000+10];
bool vis[10000+10];
int cnt;
void get_prime(int n)//筛质数
{
for(int i=2;i<=n;i++){
if(!vis[i]){
prime[cnt++] = i;
for(int j=2*i;j<=n;j+=i) vis[j] = true;
}
}
}
void solve()
{
int n;
cin>>n;
get_prime(n);
int res = 0;//记录素数对的个数
for(int i=0;i<cnt-1;i++){
if(prime[i+1]-prime[i]==2){
res++;
cout<<prime[i]<<" "<<prime[i+1]<<endl;
}
}
if(res==0) cout<<"empty"<<endl;
}
E.[蓝桥杯2022初赛] 特殊时间
直接纸上模拟比较方便。首先先从0~9中十个数字选则两个不同的数字,月份中至少包含一个0或一个1,所以选数字时至少选一个0或1。可以选择的数对为(0,1),(0,2)...(0,9),(1,2),(1,3)...(1,9)。
(0,1):3个1的情况:4*4*4 = 64(年份可排列数量*月份日期可排列数量*时间可排列数量)
3个0不满足月份日期
(0,2):3个2的情况 4*1*4 = 16
(0,3):3个3+1个0无法排列成正常月份日期
(0,4)~(0,9)情况均为0
(1,2): 3个1:4*3*4 = 48
3个2:4*1*4 = 16
(1,3):3个1:4*1*3 = 12(11月份最多到30日)
3个3开始情况均为0
(1,4):3个1:4*1*3 = 12
(1,5):3个1:4*1*3 = 12
(1,6)~(1,9):4*1*2 = 8
64+16+48+16+12*3+8*4 = 212
void solve()
{
cout<<212;
}
F.[蓝桥杯2022初赛] 求和
利用前缀和数组计算
a[1]·a[2 ]+a[1]·a[3]+...+a[1]·a[n]转化为a[i]*(a[2]+a[3]+....a[n])
(a[2]+a[3]+....a[n])可以通过前缀和数组s[n]-s[1]得出
后面的项同理
#define int long long
int a[200000+10];//原始数组
int s[200000+10];//前缀和数组
void solve()
{
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
s[i] = s[i-1]+a[i];
}
int res = 0;
for(int i=1;i<=n-1;i++){
res += (s[n]-s[i])*a[i];
}
cout<<res;
}
G: 剪切
长方形对半分面积为w*h/2
如果(x,y)在长方形对角线交点,则不止一种分割方法,否则,只有一种分割方法
void solve()
{
double w,h,x,y;
cin>>w>>h>>x>>y;
printf("%.6lf ",w*h/2);
if(abs(2*x-w)<1e-7 && abs(2*y-h)<1e-7) cout<<1;
else cout<<0;
}
H: 孙权点兵,多多乱点
遍历第2~n-1个,如果a[i]为a[i-1],a[i],a[i+1]三个数的中间数,结果数+1
void solve()
{
int n;
cin>>n;
int a[n+10];
int res = 0;
fer(i,1,n) cin>>a[i];
fer(i,2,n-1){ //for(int i=2;i<=n-1;i++)
if( (a[i]<a[i-1] && a[i]>a[i+1]) || (a[i]>a[i-1] && a[i]<a[i+1]) ) res++;
}
cout<<res;
}
I: 许攸说
如果序列长度是奇数,无法将区间分成两个长度相等的子序列
如果序列长度是偶数,数据量为1e5,可以进行排序,排序后,从a[n/2]到a[n/2+1]的数字均为符合条件的耐力值k
int a[100000+10];
void solve()
{
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+n+1);
if(n&1) cout<<0<<endl;
else{
cout<<a[n/2+1]-a[n/2]<<endl;
}
}
J: 借钱
数据量只有20,可以直接暴力查找对比,如果距离为整数,sqrt(dist)和(int)(sqrt(dist))会相等,否则不等
void solve()
{
int n,d;
cin>>n>>d;
int res = 0;
int a[n+10][d+10];
for(int i=1;i<=n;i++){
for(int j=1;j<=d;j++) cin>>a[i][j];
}
int i,j,k;
for(i=1;i<=n;i++){
for(j=i+1;j<=n;j++){
double dist=0;
for(k=1;k<=d;k++){
dist += (a[i][k]-a[j][k])*(a[i][k]-a[j][k]);
}
//cout<<sqrt(dist)<<" "<<(int)(sqrt(dist))<<endl;
if(sqrt(dist)==(int)(sqrt(dist))){
res++;
}
}
}
cout<<res;
}
K.姜维摆七星灯
题意为相邻元素乘积 <= N的序列数
用dp做,推出状态转移方程:
数据是1e9级别的,暴力会TLE,而N/j的取值只有种情况,用整除分块的方法把答案相同的dp[i][j]合在一起,然后乘起来转移
OiWiki上有整除分块相关知识:https://oi-wiki.org/math/number-theory/sqrt-decomposition/
typedef long long ll;
#define PII pair <ll,ll>
const ll mod=1e9+7;
const int N = 100000+10;
ll n,m,k;
map<ll,ll> mp;
PII g[N+10];
ll dp[100][N+10];
void solve()
{
cin>>n>>k;
for(ll l=1,r;l<=n;l=r+1){
r=n/(n/l);
g[++m]={r,r-l+1};
mp[r] = m;
}
for(int i=1;i<=m;i++){
dp[1][i]=(dp[1][i-1]+g[i].second)%mod;
}
for(int i=2;i<=k;i++){
for(int j=1;j<=m;j++){
dp[i][j]=(dp[i][j-1]+g[j].second*dp[i-1][mp[n/g[j].first]]%mod)%mod;
}
}
cout<<dp[k][m];
}
L.汉寿亭侯
这个问题关键是两点:一个是将问题转换成小球放盒子(可重复),另一个是求组合数C(a,b)的算法。求组合数有多种方法,这里我用的是卢卡斯定理的模板,lucas(a,b)C(a,b)
设要将宝石分成t堆(1<=t<=k),将问题转化一下
1.先进行分组,利用插板法把k个小球分成t组
2.然后插入到n-k+1个间隔当中去
答案最终为:
#define mod 1000000007
#define int long long
int qmi(int a, int k, int p)
{
int res = 1 % p;
while (k)
{
if (k & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
k >>= 1;
}
return res;
}
int C(int a, int b, int p) // 求组合数C(a, b)
{
if (a < b) return 0;
LL x = 1, y = 1; // x是分子,y是分母
for (int i = a, j = 1; j <= b; i --, j ++ )
{
x = (LL)x * i % p;
y = (LL) y * j % p;
}
return x * (LL)qmi(y, p - 2, p) % p;
}
int lucas(LL a, LL b, int p)
{
if (a < p && b < p) return C(a, b, p);
return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}
void solve()
{
int n,k;
cin>>n>>k;
for(int i=1;i<=k;i++){
int ans = lucas(n-k+1,i,mod)*lucas(k-1,i-1,mod)%mod;
cout<<ans<<endl;
}
}
M.赵子龙七进七出
用bfs处理最小步数,邻接矩阵存储图,搜索的时候三次跳跃才算一步,所以需要开到二维数组来记录
queue<PII>q;
int vis[100000+10][3];
int dp[100000+10][3];
vector<int>g[100000+10];
int s,t;
int n,m;
void bfs(){
dp[s][0] = 0;
vis[s][0] = 1;
q.push({s,0});
while(!q.empty()){
auto t = q.front();
q.pop();
int tx = t.first;
int ty = t.second;
int y = (ty+1)%3;
for(auto it:g[tx]){
if(!vis[it][y]){
dp[it][y] = dp[tx][ty]+1;
q.push({it,y});
vis[it][y] = 1;
}
}
}
}
void solve()
{
cin>>n>>m;
for(int i=1;i<=m;i++){
int a,b;
cin>>a>>b;
g[a].push_back(b);
}
cin>>s>>t;
bfs();
if(!vis[t][0]) cout<<-1<<endl;
else cout<<dp[t][0]/3<<endl;
}