河南萌新联赛2025第(八)场:南阳理工学院
我们好不容易,我们身不由己
我怕时间太快,不够将你看仔细
我怕时间太慢,日夜担心失去你
恨不得一夜之间白头永不分离
河南萌新联赛2025第(八)场:南阳理工学院
河南萌新联赛2025第(八)场:南阳理工学院_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ
第八场;赛时没有参加,赛后补的题;个人感觉南阳理工的题目都还是比较不错的,思维很强,题目也都比较有意思;
整体的题目难度如下:
简单:A K L I
中等:F B E D
中等偏难:G H J
困难:C
目录
- 河南萌新联赛2025第(八)场:南阳理工学院
- A-什么?!竟然是签到
- K-仓库管理
- L-幸运数值
- I-随从交换
- F-2026
- E-魔法排斥
A-什么?!竟然是签到
简单的小模拟,依据题意遍历即可
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define pii pair<int,int>
#define fi first
#define se second
#define lb(x) ((x)&(-x))
#define lc u<<1
#define rc u<<1|1
const int inf=0x3f3f3f3f;
const int N=1e5+5;
void slove(){int n;cin>>n;string s;cin>>s;int an=0;for(int i=0;i<s.size()-4;i++){if(s[i]=='X'&&s[i+1]=='X'&&s[i+2]=='O'&&s[i+3]=='O')an++;}cout<<an;
}
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int _=1;//cin>>_;while(_--)slove();return 0;
}
K-仓库管理
依据题意可以判断出,当k>=n∗2k>=n^*2k>=n∗2 时,存在一种方案。首先给n个人员分配钥匙,接着我们可以让第1个仓库放第2个仓库的钥匙,让第2个仓库放第3个仓库的钥匙,一直到第n个合库放第1个仓库的钥匙,这样便构成了一个环,从任意一个仓库打卡都可以到达任意一个合库。注意要特判k==1&&n==1这种情况。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define endl '\n'
#define pii pair<int,int>
#define fi first
#define se second
#define lb(x) ((x)&(-x));
#define lc u<<1
#define rc u<<1|1
const int inf=0x3f3f3f3f;
const int N=1e5+5;
void slove(){int n,k;cin>>n>>k;if(k>=2*n) cout<<"YES"<<endl;else if(k==1&&n==1) cout<<"YES"<<endl;else cout<<"NO"<<endl;
}
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int _=1;cin>>_;while(_--)slove();return 0;
}
import sys
input=sys.stdin.readlineans=[]
def slove():n,k=map(int,input().split())if k>=2*n : ans.append('YES')elif k==1 and n==1 : ans.append('YES')else : ans.append('NO')_=1
_=int(input())
while _ :_-=1slove()
print('\n'.join(ans))
L-幸运数值
子序列按位与结果的二进制中第 kk 位为 1,当且仅当子序列中所有元素在该位均为 1。因此,幸福值之和。
可拆分为:统计每位上有多少个子序列满足条件,再对所有位的贡献求和。
设第k位上有cntkk\text{位上有cnt}_kk位上有cntk个元素的二进制表示在该位为1。
这些元素组成的非空子序列个数为2kcnt−1(2^\mathrm{cnt}_k-1(2kcnt−1(排除空集)
第k位的贡献即为2kcnt−1k\text{位的贡献即为2}^\mathrm{cnt}_k-1k位的贡献即为2kcnt−1
计算总和:总幸福值等于所有二进制位贡献之和:ans=∑k=0max_bit(2cntk−1)=\sum_{k=0}^{\max\_\mathrm{bit}}(2^{\mathrm{cnt}_k}-1)=∑k=0max_bit(2cntk−1)
其中max_bit取20(106<220)。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define endl '\n'
#define pii pair<int,int>
#define fi first
#define se second
#define lb(x) ((x)&(-x))
#define lc u<<1
#define rc u<<1|1
const int inf=0x3f3f3f3f;
const int N=1e6+5;
const int M=1e9+7;
int a[N];
int er[N],cn[N];
void slove(){int n;cin>>n;for(int i=1;i<=n;i++)cin>>a[i];er[0]=1;for(int i=1;i<=n;i++)er[i]=(er[i-1]*2)%M;for(int i=1;i<=n;i++){int x=a[i];for(int i=0;i<20;i++){if(x&(1<<i))cn[i]++;}}int an=0;for(int i=0;i<20;i++)an=(an+er[cn[i]]-1)%M;cout<<an%M;
}
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int _=1;//cin>>_;while(_--)slove();return 0;
}
I-随从交换
很经典的约瑟夫问题!但是题目的数据范围很大,不够递推循环模拟
所以此时就可以直接套用结论,O(1)得出最后一个选手的位置
设:N=总人数 Y=最终存活的人
则可以推出:N=p+2x ( a<2x ) , Y=2p+1
证明也很简单,可以列表观察发现,当总人数为2x时,总是第1个人活到最后;所以在每一轮减少人数时,当人数首次到达2i时,下一个人就是货到最后的人
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define pii pair<int,int>
#define fi first
#define se second
#define lb(x) ((x)&(-x))
#define lc u<<1
#define rc u<<1|1
const int inf=0x3f3f3f3f;
const int N=1e5+5;
void slove(){int n;cin>>n;int p=n-pow(2,(int)log2(n));cout<<2*p+1;
}
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int _=1;//cin>>_;while(_--)slove();return 0;
}
import sys
input=sys.stdin.readline
from math import log2n=int(input())
p=n-2**int(log2(n))
print(2*p+1)
F-2026
初看题目看着感觉和麻烦,但是仔细观察可以发现2026 的因子有1, 2, 1013, 2026
即两个因子对(1,2026)(2,1013)
所以我们可以使[a,b]中的1的倍数的数量乘以[c,d]中2026的倍数的数量和[a,b]中的2的倍数的数量乘以[c,d]中1013的倍数的数量
另一组也是如此:即[a,b]中的2026的倍数的数量乘以[c,d]中1的倍数的数量和[a,b]中的1013的倍数的数量乘以[c,d]中2的倍数的数量
但是显然这样会出现重复的情况;所以就可以利用容斥原理:在让[a,b]中的1的倍数的数量乘以[c,d]中2026的倍数的数量时,将[a,b]中符合条件的数中又是2026, 1013倍数的数减去;在让[a,b]中的2的倍数的数量乘以[c,d]中1013的倍数的数量时,将[a,b]中符合条件的数中又是2026倍数的数减去;另两个区间同理;
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define endl '\n'
#define pii pair<int,int>
#define fi first
#define se second
#define lb(x) ((x)&(-x))
#define lc u<<1
#define rc u<<1|1
const int inf=0x3f3f3f3f;
const int N=1e5+5;
void slove(){int a,b,c,d;cin>>a>>b>>c>>d;int l1=b/2026-(a-1)/2026;int r1=d/2026-(c-1)/2026;int l2=b/1013-(a-1)/1013-l1;int r2=d/1013-(c-1)/1013-r1;int an=(d-c+1-r1-r2)*l1+(b-a+1-l1-l2)*r1;an+=(d/2-(c-1)/2-r1)*l2+(b/2-(a-1)/2-l1)*r2;an+=l1*(r1+r2)+l2*r1;cout<<an<<endl;
}
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int _=1;cin>>_;while(_--)slove();return 0;
}
import sys
input=sys.stdin.readlineans=[]
def slove():a,b,c,d=map(int,input().split())l1=b//2026-(a-1)//2026;r1=d//2026-(c-1)//2026;l2=b//1013-(a-1)//1013-l1r2=d//1013-(c-1)//1013-r1an=(d-c+1-r1-r2)*l1+(b-a+1-l1-l2)*r1an+=(d//2-(c-1)//2-r1)*l2+(b//2-(a-1)//2-l1)*r2an+=l1*(r1+r2)+l2*r1ans.append(str(an))_=int(input())
while _:_-=1slove()
print('\n'.join(ans))
E-魔法排斥
一道数论的题目;
所有不大于n且与n互质的正整数之和可以通过欧拉函数求得,具体公式为:与n互质的数之和=n⋅φ(\cdot\varphi(⋅φ(n)/2
其中,φ(\varphi(φ(n)表示欧拉函数,即1到n中与n互质的数的个数。
互质数的对称性:对于任意与n互质的数x,有gcd(n,x)=1。根据更相减损术gcd(n,x)=gcd(n,n−x)\gcd(n,x)=\gcd(n,n-x)gcd(n,x)=gcd(n,n−x) ,因此,与n互质的数x和n- x成对出现。
总和计算:共有 φ(n)个与n互质的数,这些数可以组成φ(n)/2 对,每对的和为n。因此,所有与n互质的数之和为 n/2·φ(n)。
代码实现并不复杂;
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define endl '\n'
#define pii pair<int,int>
#define fi first
#define se second
#define lb(x) ((x)&(-x))
#define lc u<<1
#define rc u<<1|1
const int inf=0x3f3f3f3f;
const int N=1e5+5;
int ffjp(int n){int an=n,t=n;for(int i=2;i<=t/i;i++){if(t%i==0){an=an/i*(i-1);while(t%i==0) t/=i;}}if(t>1) an=an/t*(t-1);return an;
}
void slove(){int n;cin>>n;if(n==1){cout<<1<<endl;return ;}cout<<n*ffjp(n)/2<<endl;
}
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int _=1;cin>>_;while(_--)slove();return 0;
}
这次的题目还是很不错的,后面的题目等日后精进在补;薄弱点依旧是数论的部分,太难推了!!