【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;
}
posted @   MNNUACM_2024ZY  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示