2024/8/8训练

A - 无线网络整点栅格统计

题目链接

算法:模拟

题目大意

给你一个n*m的网格,然后输出每一个点作为顶点能构成的正方形数量(可以为斜正方形).

算法思路

本身题目数据是很小的,可以通过n^2的时间复杂度枚举每一个顶点,然后再通过n平方的时间复杂度枚举出另一个对角顶点,判断剩下的两个点是否在网格里面即可.这样的话时间复杂度是n的四次方时间复杂度了,可以通过.
我们可以知道当以A为顶点的斜正方形一定可以被过A的正正方形包围,那么我们每个店只需要求出过这个点所能构成的正正方形数量即可.
至于如何求每个点构成的正正方形数量可以根据个人理解来求.
我的思路是:我们可以通过记录A点左边,上边,斜左上角,本身的正正方形数量,然后这样过A点的正正方形数量就是四个之和.

代码

#include<bits/stdc++.h>
#define ll long long
const int N = 1e5+7;
int dx[]= {1,-1,0,0,1,1,-1,-1};
int dy[]= {0,0,1,-1,1,-1,1,-1};
using namespace std;
struct Node {
	//自身 左边 上边
	//左上角
	int ct,lt,fr;
	int lf;
};
Node a[107][107];
int n,m;
int ce(int x,int y) {
	return min(n+1-x,m+1-y);
}
int celf(int x,int y) {
	return min(x-1,m+1-1)*min(y-1,n+1-1);
}
int ti[107][107];
int tj[107][107];
void slove() {
	for(int i=1; i<=100; ++i) {
		ti[0][i]=-2;
		tj[i][0]=-2;
	}
	cin>>n>>m;
	for(int i=1; i<=(ll)ceil(1.0*(n+1)/2); ++i) {
		for(int j=1; j<=(ll)ceil(1.0*(m+1)/2); ++j) {
			a[i][j].ct=ce(i,j);
			if(i<=m+1) {
				ti[i][j]=ti[i-1][j]+1;
				if(i!=1) a[i][j].fr=a[i-1][j].ct+max(0,(a[i-1][j].fr+-ti[i][j]));
			} else {
				//需要去掉刚好到i-1的情况
				a[i][j].fr=a[i-1][j].fr;
			}
			if(j<=n+1) {
				tj[i][j]=tj[i][j-1]+1;
				if(j!=1) a[i][j].lt=a[i][j-1].ct+max(0,(a[i][j-1].lt+-tj[i][j]));
			} else {
				//需要去掉刚好到j-1的情况
				a[i][j].lt=a[i][j-1].lt;
			}
			a[i][j].lf=celf(i,j);
		}
	}


	for(int i=1; i<=(ll)ceil(1.0*(n+1)/2); ++i) {
		for(int j=1; j<=(ll)ceil(1.0*(m+1)/2); ++j) {
			cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
		}
		if((m+1)%2==0) {
			for(int j=(ll)ceil(1.0*(m+1)/2); j>=1; --j) {
				cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
			}
		} else {
			for(int j=(ll)ceil(1.0*(m+1)/2)-1; j>=1; --j) {
				cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
			}
		}

		cout<<endl;
	}
	if((n+1)%2==0) {
		for(int i=(ll)ceil(1.0*(n+1)/2); i>=1; --i) {
			for(int j=1; j<=(ll)ceil(1.0*(m+1)/2); ++j) {
				cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
			}
			if((m+1)%2==0) {
				for(int j=(ll)ceil(1.0*(m+1)/2); j>=1; --j) {
					cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
				}
			} else {
				for(int j=(ll)ceil(1.0*(m+1)/2)-1; j>=1; --j) {
					cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
				}
			}

			cout<<endl;
		}
	} else {
		for(int i=(ll)ceil(1.0*(n+1)/2)-1; i>=1; --i) {
			for(int j=1; j<=(ll)ceil(1.0*(m+1)/2); ++j) {
				cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
			}
			if((m+1)%2==0) {
				for(int j=(ll)ceil(1.0*(m+1)/2); j>=1; --j) {
					cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
				}
			} else {
				for(int j=(ll)ceil(1.0*(m+1)/2)-1; j>=1; --j) {
					cout<<a[i][j].ct+a[i][j].fr+a[i][j].lt+a[i][j].lf<<" ";
				}
			}
			cout<<endl;
		}
	}

	return;
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	int t = 1;
//	cin>>t;
	while(t--) {
		slove();
		cout<<endl;
	}
	return 0;
}

C. Liar

题目链接

算法:思维

题目大意

有n个数,这些个数的总和为s,这些数有真有假,输出最多有多少个数是真的

算法思路

因为当这个数为假的时候,我们可以把这个数设为无穷数,那么当n个数都为真无法满足总和为s的情况,我们可以让前n-1个数都为真,然后通过最后一个数进行调节,满足n个数的总和为s的情况

代码

#include<bits/stdc++.h>
#define ll long long
const int N = 1e5+7;
int dx[]= {1,-1,0,0,1,1,-1,-1};
int dy[]= {0,0,1,-1,1,-1,1,-1};
using namespace std;
ll a[N];
void slove() {
	ll n,s;
	cin>>n>>s;
	for(int i=1; i<=n; ++i) cin>>a[i];
	sort(a+1,a+n+1);
	ll ans = 0;
	for(int i=1; i<=n; ++i) {
		ans+=a[i];
	}
	if(ans==s) {
		cout<<n;
		return;
	}
	cout<<n-1;
}
int main() {
	int t = 1;
//	cin>>t;
	while(t--) {
		slove();
		cout<<endl;
	}
	return 0;
}

Magic LCM

题目链接

算法:数学+模拟+贪心

题目大意

给你一个长度为n的数组,然后你可以进行无数次操作:选择两个不同的数(x,y),设x为gcd(x,y),y为lcm(x,y).
求出最后这个数组之和的最大值.

算法思路

对于两个数进行gcd和lcm赋值,其实gcd就是公共因子,lcm就是公共因子不同的因子.
而且因子和因子之间互不打扰.
那么我们就可以把数组里面的每一个数进行拆解,拆解成质因子,依次求出进行操作以后的最大值.
又因为操作就是将公共因子乘不同的因子,那么我们可以让质因子个数多的先提供,求出一个当前的最大值.
比如:9 6 4 27 10 12这个数组
9->3
3
6->23
4->2
2
27->333
10->25
12->2
23
那么我们可以先让4提供两个2,27提供三个3,10提供一个5,这样组成540.
剩下的数
3
3
23
2
2
2*3
注意,质因子之间相互独立,所以不用在意是具体是谁提供的
我们继续两个2,两个3组成36
一个2.一个3
组成6
一个2.一个3
组成6
这样把所有的质因子都用掉以后
还剩下两个数,这两个数就是1

#include<bits/stdc++.h>
#define ll long long
const int N = 1e6+7;
const int M = 998244353;
int dx[]= {1,-1,0,0,1,1,-1,-1};
int dy[]= {0,0,1,-1,1,-1,1,-1};
using namespace std;
struct Node {
	map<int,ll> mp;
	set<int> st;
};
Node a[N];
priority_queue<ll, vector<ll>, less<ll>> q[N];
set<int> tst;
ll q_pow(ll n,ll x) {
	ll sum=1;
	while(x) {
		if(x&1) sum*=n;
		x>>=1;
		n*=n;
		n%=M;
		sum%=M;
	}
	sum%=M;
	return sum;
}
void slove() {
	ll n;
	cin>>n;
	for(int i=1,t; i<=n; ++i) {
		cin>>t;
		for(auto &v:a[t].st) {
			tst.insert(v);
			q[v].push(a[t].mp[v]);
		}
	}
	ll ans = 0;
	int sz = 0;
	int flag = 0;
	while(1) {
		flag = 0;
		ll tans = 1;
		for(auto it = tst.begin(); it != tst.end();) {
			if(q[*it].empty()) {
				it = tst.erase(it);
			} else {
				flag = 1;
				ll t = q_pow(*it,q[*it].top());
				q[*it].pop();
				tans*=t;
				tans%=M;
				++it;
			}
		}
		ans += tans;
		ans%=M;
		sz++;
		if(flag == 0) break;
	}
	cout<<ans+n-sz;
	return;
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	a[1].mp[1]=1;
	for(int i=2; i<=1e6; ++i) {
		int flag = 0;
		for(int j=2; j*j<=i; ++j) {
			if(i%j==0) {
				flag = 1;
				int t = i/j;
				for(auto &v:a[t].st) {
					a[i].mp[v]+=a[t].mp[v];
					a[i].st.insert(v);
				}
				a[i].mp[j]++;
				a[i].st.insert(j);
				break;
			}
		}
		if(flag == 0) {
			a[i].mp[i]++;
			a[i].st.insert(i);
		}
	}

//	int mx = 0;
//	for(int i=1;i<=1e6;++i) {
//		mx = max(mx,(int)a[i].st.size());
//	}
//	cout<<mx;

	int t = 1;
	cin>>t;
	while(t--) {
		slove();
		cout<<endl;
	}
	return 0;
}

这个代码部分main里面对如何在nlogn的时间复杂度求出1-n里面每个数分别有哪些因子可以重点看一下.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值