贪心yyds!
牛马B题卡我好久,不要在栈内开邻接表!少开邻接表!除了方便一无所有!
题意:
有n组数据,给你ai bi,你可以选ai的一个因子di,尽量使得连续的bi*di相等,求bi*di的值最少的改变次数是多少。
思路:
ai=t*di,aj=k*dj
ai*bi=t*di*bi,aj*bj=k*dj*bj
如果存在num=di*bi==dj*bj,很显然num是ai*bi和aj*bj的一个公因子,由于d是我们可以自己凑的,所以只需要判断对于bi来说这个公因子是否存在即可。
在两个数中,当(t,k)!=1的时候显然可以让d增加一倍的gcd(t,k)也必然成立,所以可以令num为ai*bi和aj*bj的一个gcd,然后去查这个gcd是不是b的倍数。
在很多数中,就需要让gcd是所有数的gcd,并且需要让gcd是所有b的lcm的倍数,出现不行的数就从当前数开始更新gcd和lcm的值,ans++。
#include <bits/stdc++.h>
using namespace std;
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
#define i64 __int64
#define int ll
#define pb push_back
#define eb emplace_back
#define m_p make_pair
#define mod 998244353
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define fi first
#define se second
#define inf 0x3f3f3f3f
const int N = 3e5 + 50;
//__builtin_ctzll(x);后导0的个数
//__builtin_popcount计算二进制中1的个数
int a[N], b[N];
void work() {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i] >> b[i];
}
int d=a[1]*b[1], lcm=b[1], ans = 1, maxx = b[1];
for (int i = 2; i <= n; ++i) {
d = __gcd(d, a[i] * b[i]);
lcm = b[i] * lcm / __gcd(b[i], lcm);
if (d % lcm) {
d = a[i] * b[i];
lcm = b[i];maxx = b[i];ans++;
}
}
cout << ans << '\n';
}
signed main() {
io;
int t;
cin >> t;
while (t--) {
work();
}
return 0;
}
思路:
正了加负,负了加正,保持前缀和一直向0靠,只要不是全0串就都可以做到。
#include <bits/stdc++.h>
using namespace std;
#define io ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
typedef long long ll;
#define i64 __int64
//#define int ll
#define pb push_back
#define eb emplace_back
#define m_p make_pair
#define mod 998244353
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define fi first
#define se second
#define inf 0x3f3f3f3f
const int N = 3e5 + 50;
//__builtin_ctzll(x);后导0的个数
//__builtin_popcount计算二进制中1的个数
int a[N], ans[N];
void work() {
int n;
cin >> n;
bool flag = 0;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
if (a[i] != 0)
flag = 1;
}
if (!flag) {
cout << "No\n";
return;
}
sort(a + 1, a + 1 + n);
int l = 1, r = n, tmp = 0;
int maxx = 0;
while (l <= r) {
if (maxx <= 0) {
ans[++tmp] = a[r--];
maxx += ans[tmp];
} else {
ans[++tmp] = a[l++];
maxx += ans[tmp];
}
}
cout << "YES\n";
for (int i = 1; i <= n; ++i) {
cout << ans[i] << " ";
}
cout << '\n';
}
signed main() {
io;
int t;
cin >> t;
while (t--) {
work();
}
return 0;
}
文章介绍了两道编程竞赛题目,第一题通过求解gcd和lcm来减少乘积的改变次数,第二题利用前缀和思想调整序列达到目标状态。核心是贪心策略和数学优化。
282

被折叠的 条评论
为什么被折叠?



