【vjudge训练记录】大一寒假专项训练——枚举算法
训练情况
A题
给定 \((x,y)\),倒着枚举地毯的范围是否覆盖 \((x,y)\),如果覆盖直接输出,如果全部枚举完都没有则输出 -1
点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'
using namespace std;
void solve(){
int n; cin>>n;
int x[n+1],y[n+1],a[n+1],b[n+1];
for(int i = 1;i<=n;i++){
cin>>x[i]>>y[i]>>a[i]>>b[i];
}
int xx,yy; cin>>xx>>yy;
for(int i = n;i;i--){
if(xx >= x[i] && xx <= x[i]+a[i] && yy >= y[i] && yy <= y[i]+b[i]){
cout<<i<<endl;
return;
}
}
cout<<-1<<endl;
}
signed main(){
// int T; cin>>T; while(T--)
solve();
return 0;
}
B题
求有多少对 \((P,Q)\) 使得 \(\gcd(P,Q)=x_0\),\(\operatorname{lcm}(P,Q)=y_0\)
另外有一个性质就是 \(\gcd(P,Q) \times \operatorname{lcm}(P,Q) = P \times Q\)
所以我们已知这三个条件,我们可以枚举 \(P\),然后判断是否存在一个 \(Q\) 满足上述三个条件,由于成对存在,所以我们枚举的上界只需要到 \(\sqrt{nm}\),然后 \((P,Q)\) 和 \((Q,P)\) 视为两种不同的答案,最后对数需要乘二,注意一下 \(P = Q\) 的情况要减掉
点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'
using namespace std;
void solve(){
int m,n;
cin>>m>>n;
int ans = 0;
n*=m;
for(int i=1;i<=sqrt(n);i++){
if(n%i==0&&__gcd(i,n/i)==m) ans++;
}
cout<<ans*2-(m==n/m)<<endl;
}
signed main(){
// int T; cin>>T; while(T--)
solve();
return 0;
}
C题
有 \(n\) 个数,要满足 \(\lvert a_i - a_{i-1} \rvert\) 覆盖 \([1,n)\) 的所有整数,所以我们直接枚举,两个元素差的绝对值如果超过上述范围则无法满足条件,反之则存在。这题有一个小性质,排不排序都不会影响最终差绝对值覆盖的区间。
点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'
using namespace std;
void solve(){
int n; cin>>n;
int a[n+1];
for(int i = 1;i<=n;i++) cin>>a[i];
for(int i = 2;i<=n;i++){
int x = abs(a[i] - a[i-1]);
if(x > n-1 || x < 1){
cout<<"Not jolly"<<endl;
return;
}
}
cout<<"Jolly"<<endl;
}
signed main(){
// int T; cin>>T; while(T--)
solve();
return 0;
}
D题
找数列中有多少对 \((i,j,k)\) 使得 \(a_i + a_j = a_k\)(\(i,j,k\) 互不相同),所以我们可以开一个数组表示某个数字是否出现过,然后枚举两个数 \(i,j\),判断是否存在 \(a_k = a_i + a_j\) 中的 \(a_k\) 是否存在,题目所述 其中有多少个数,恰好等于集合中另外两个(不同的)数之和? \(a_k\) 对答案的贡献最多为 \(1\),所以答案自增后 \(a_k\) 需要标记成没出现过
点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define endl '\n'
using namespace std;
void solve(){
int n; cin>>n;
int a[n + 1];
map<int,bool> vis;
for(int i = 1;i<=n;i++) cin>>a[i],vis[a[i]]=1;
int ans = 0;
for(int i = 1;i<=n;i++){
for(int j = i+1;j<=n;j++){
if(vis[a[i] + a[j]]) ans++,vis[a[i]+a[j]]=0;
}
}
cout<<ans<<endl;
}
signed main(){
// int T; cin>>T; while(T--)
solve();
return 0;
}
E题
直接枚举区间 \([l,r]\) 的时间复杂度为 \(O(n^2)\) 会超时,对于区间求和的问题我们容易想到前缀和,但是我们需要处理区间是 \(k\) 的倍数,我们考虑对前缀和对 \(k\) 取模(取余数),如果位置 \(l,r\) 的前缀和 \((p_l \mod k) = (p_r \mod k)\) 则说明区间 \([l,r]\) 的和一定是 \(k\) 的倍数,因为 \((x \mod b) = ((x + kb) \mod b)\),所以我们需要统计 \(p_i\) 余数的出现次数,遍历的时候查询当前位置余数在前面出现了几次,就是有几个区间,答案加上区间个数即可,注意一下初始条件,详情见代码
点击查看代码
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
void solve(){
int n,k; cin>>n>>k;
int a[n+1],pre[n+1],cnt[n+1];
pre[0] = 0;
for(int i = 1;i<=n;i++) cin>>a[i],cnt[i] = 0;
for(int i = 1;i<=n;i++) pre[i] = pre[i-1] + a[i];
for(int i = 1;i<=n;i++) pre[i] %= k;
cnt[0] = 1;
int ans = 0;
for(int i = 1;i<=n;i++){
ans += cnt[pre[i]];
cnt[pre[i]]++;
}
cout<<ans<<endl;
}
signed main(){
// int T; cin>>T; while(T--)
solve();
return 0;
}
F题
求有多少对 \((i,j)\) 使得 \(a_i\) 是 \(a_j\) 的倍数,我们先统计一个数 \(x\) 在数列中的出现次数,考虑枚举 \(a_i\) 的倍数,枚举的上界为 \(k \times a_i \le max(a_i)\),如果 \(k \times a_i\) 至少出现了一次,则必定存在 \((a_i,k \times ai)\) 这一对,答案为倍数的出现次数之和,即 \(\sum{v_{k a_i}}\)
点击查看代码
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 5e5 + 3;
int n,a[N],v[N],ma;
int ans;
void solve(){
cin>>n;
for(int i = 1;i<=n;i++) cin>>a[i],v[a[i]]++,ma=max(ma,a[i]);
for(int i = 1;i<=n;i++){
for(int j = 1;a[i]*j<=ma;j++){
ans+= v[a[i]*j];
}
}
cout<<ans-n<<endl;
}
signed main(){
// int T; cin>>T; while(T--)
solve();
return 0;
}
G题
羊和狼在相邻的两个动物相同和不同时的说法是相反的,我们容易发现,只要固定了前两个动物,共有四种情况 (狼,狼)、(狼,羊)、(羊,羊)、(羊,狼),后面的动物都可以根据题目所给的说法计算出来,由于这题是一个环,所以判断首尾动物的说法是否自相矛盾,即前两只动物的说法是否和最后两只动物的说法自相矛盾,如果四种情况都自相矛盾则说明无解,否则任意输出一种合法情况均正确
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 3;
int n; char s[N];
bool flag = false;
char ans[N];
bool pd(){
bool fflag = true;
if(s[0] == 'o' && ans[0] == 'S'){
if(ans[1] != ans[n-1]) fflag = false;
}
if(s[0] == 'x' && ans[0] == 'S'){
if(ans[1] == ans[n-1]) fflag = false;
}
if(s[0] == 'o' && ans[0] == 'W'){
if(ans[1] == ans[n-1]) fflag = false;
}
if(s[0] == 'x' && ans[0] == 'W'){
if(ans[1] != ans[n-1]) fflag = false;
}
//
if(s[n-1] == 'o' && ans[n-1] == 'S'){
if(ans[0] != ans[n-2]) fflag = false;
}
if(s[n-1] == 'x' && ans[n-1] == 'S'){
if(ans[0] == ans[n-2]) fflag = false;
}
if(s[n-1] == 'o' && ans[n-1] == 'W'){
if(ans[0] == ans[n-2]) fflag = false;
}
if(s[n-1] == 'x' && ans[n-1] == 'W'){
if(ans[0] != ans[n-2]) fflag = false;
}
return fflag;
}
void mj(){
for(int i = 1;i<n-1;i++){
//for(int j = 0;j<n;j++) cout<<ans[j];
if(ans[i] == 'S'){
if(s[i] == 'o') ans[i+1] = ans[i-1];
else {
if(ans[i-1] == 'S') ans[i+1] = 'W';
else ans[i+1] = 'S';
}
} else {
if(s[i] == 'x') ans[i+1] = ans[i-1];
else {
if(ans[i-1] == 'S') ans[i+1] = 'W';
else ans[i+1] = 'S';
}
}
}
}
void SS(){
if(flag) return;
ans[0] = 'S'; ans[1] = 'S';
mj();
if(pd()){
flag = true;
for(int i = 0;i<n;i++) cout<<ans[i];
}
}
void SW(){
if(flag) return;
ans[0] = 'S'; ans[1] = 'W';
mj();
if(pd()){
flag = true;
for(int i = 0;i<n;i++) cout<<ans[i];
}
}
void WS(){
if(flag) return;
ans[0] = 'W'; ans[1] = 'S';
mj();
if(pd()){
flag = true;
for(int i = 0;i<n;i++) cout<<ans[i];
}
}
void WW(){
if(flag) return;
ans[0] = 'W'; ans[1] = 'W';
mj();
if(pd()){
flag = true;
for(int i = 0;i<n;i++) cout<<ans[i];
}
}
int main(){
cin>>n;
cin>>s;
SS();
SW();
WS();
WW();
if(!flag) cout<<-1<<endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端