Problem J. Sum Plus Product
题解:
可以判断出是不变量,所以答案就是 - 1。
代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#define int long long
#define double long double
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 2e5 + 10;
const int mod = 998244353;
int n, a[N];
void solve() {
cin >> n ;
for(int i = 1; i <= n ; i ++) cin >> a[i];
for(int i = 1; i < n; i ++){
a[i + 1] = (a[i] * a[i + 1] % mod + a[i] + a[i + 1]) % mod;
}
cout << a[n] << '\n';
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int t;
cin >> t;
while(t--){
solve();
}
}
Problem H. Shortest Path in GCD Graph
题解:
做法. 首先最短路长度不超过2,因为对任意(𝑥, 𝑦),沿路径𝑥 → 1 → 𝑦即可得到一条长度为2的路径。最短路长度为1当且仅当𝑔𝑐𝑑 (𝑥, 𝑦) = 1,否则等价于询问[1, 𝑛]中满足𝑔𝑐𝑑 (𝑥, 𝑧) =1且𝑔𝑐𝑑 (𝑦, 𝑧) = 1的𝑧的数量,分解𝑥, 𝑦后用容斥可以解决。注意𝑔𝑐𝑑 (𝑥, 𝑦) = 2时,直接𝑥 → 𝑦也是一条长度为2的路径。
代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#define int long long
#define double long double
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 2e5 + 10;
const int mod = 998244353;
int n, nn, q, ans;
vector<int> d;
int gcd(int x, int y){
return x % y ? gcd(y, x % y) : y;
}
void init(int n){
for(int i = 2; i * i <= n; i ++){
if(n % i) continue;
d.push_back(i);
while(n % i == 0) n /= i;
}
if(n > 1) d.push_back(n);
}
void dfs(int ii, int cnt, int res){
if(ii == nn){
if(cnt == 0) return;
if(cnt % 2) ans += n / res;
else ans -= n / res;
return;
}
dfs(ii + 1, cnt, res);
dfs(ii + 1, cnt + 1, res * d[ii]);
}
void solve() {
cin >> n >> q;
int u, v;
while(q--){
cin >> u >> v;
if(gcd(u, v) == 1) cout << "1 1\n";
else{
ans = 0;
cout << "2 ";
d.clear();
init(u), init(v);
sort(d.begin(), d.end());
d.erase(unique(d.begin(), d.end()), d.end());
nn = d.size();
dfs(0, 0, 1);
cout << n - ans + (gcd(u, v) == 2) << '\n';
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int t = 1;
//cin >> t;
while(t--){
solve();
}
}
Problem G. Matryoshka Doll
题解:
做法. 𝑑𝑝 (𝑥, 𝑦)表示将前𝑥个套娃分成𝑦组的方案数,转移为
𝑑𝑝 (𝑥, 𝑦) = 𝑑𝑝 (𝑥 − 1, 𝑦 − 1) + 𝑑𝑝 (𝑥 − 1, 𝑦) · max{0, 𝑦 − 𝑓 (𝑥)}.
其中𝑓 (𝑥)表示满足1 ≤ 𝑧 < 𝑥且𝑎𝑥 − 𝑟 < 𝑎𝑧 ≤ 𝑎𝑥 的𝑧的个数。
代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#include<set>
#include<stack>
#define int long long
#define double long double
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 5e3 + 10;
const int mod = 998244353;
int n, k, r, a[N], dp[N][N];
void solve()
{
cin >> n >> k >> r;
for(int i = 0; i <= n; i++){
for(int j = 0; j <= k; j ++){
dp[i][j] = 0;
}
}
for(int i = 1; i <= n; i++){
cin >> a[i];
}
int p = 0;
dp[0][0] = 1;
for(int i = 1; i <= n; i++){
while(p + 1 < i && a[p + 1] + r <= a[i]) p ++;
int s = i - p - 1;
for(int j = s + 1; j <= i; j++){
dp[i] [j] = ((j - s) * dp[i - 1][j] + dp[i - 1][j - 1]) % mod;
}
}
cout << dp[n][k] << '\n';
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int t = 1;
cin >> t;
while(t--){
solve();
}
}
Problem C. Fast Bubble Sort
题解:
假设𝑃 = 𝑛1𝜆1𝑛2𝜆2 · · · 𝑛𝑘 𝜆𝑘 ,则𝐵(𝑃) = 𝜆1𝑛1𝜆2𝑛2 · · · 𝜆𝑘𝑛𝑘 ,其中𝑛1, · · · , 𝑛𝑘 为从左到右的局
部最大值且有
𝑛1 < 𝑛2 < · · · < 𝑛𝑘,
则不难证明答案为非空𝜆𝑖 的个数。
将询问离线,每次从𝑛到1倒序扫描左端点𝑙并回答所有左端点为𝑙的询问。对于每个固定的左端
点𝑙,[𝑙, 𝑛]中从左到右的局部最大值可以通过单调栈维护,局部最大值插入/删除对于答案的影
响可以用树状数组/线段树快速更新/求解。
代码:
// #pragma comment(linker, "/STACK:102400000,102400000")
#pragma GCC optimize("O3")
#pragma GCC optimize("O2")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx")
// #pragma GCC optimize("trapv")
#include<bits/stdc++.h>
// #include <bits/extc++.h>
#define int long long
#define double long double
// #define i128 long long
// #define double long double
using namespace std;
#define rep(i,n) for (int i=0;i<(int)(n);++i)
#define rep1(i,n) for (int i=1;i<=(int)(n);++i)
#define range(x) begin(x), end(x)
#define sz(x) (int)(x).size()
#define pb push_back
#define F first
#define S second
typedef long long ll;
typedef unsigned long long ull;
// typedef long double ld;
typedef pair<int, int> pii;
typedef vector<int> vi;
namespace internal {
// @param n `0 <= n`
// @return minimum non-negative `x` s.t. `n <= 2**x`
int ceil_pow2(int n) {
int x = 0;
while ((1U << x) < (unsigned int)(n)) x++;
return x;
}
// @param n `1 <= n`
// @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0`
// constexpr int bsf_constexpr(unsigned int n) {
// int x = 0;
// while (!(n & (1 << x))) x++;
// return x;
// }
// @param n `1 <= n`
// @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0`
int bsf(unsigned int n) {
#ifdef _MSC_VER
unsigned long index;
_BitScanForward(&index, n);
return index;
#else
return __builtin_ctz(n);
#endif
}
} // namespace internal
template <class S, S (*op)(S, S), S (*e)()> struct segtree {
public:
segtree() : segtree(0) {}
segtree(int n) : segtree(std::vector<S>(n, e())) {}
segtree(const std::vector<S>& v) : _n((int)(v.size())) {
log = internal::ceil_pow2(_n);
size = 1 << log;
d = std::vector<S>(2 * size, e());
for (int i = 0; i < _n; i++) d[size + i] = v[i];
for (int i = size - 1; i >= 1; i--) {
update(i);
}
}
void set(int p, S x) {
assert(0 <= p && p < _n);
p += size;
d[p] = x;
for (int i = 1; i <= log; i++) update(p >> i);
}
S get(int p) {
assert(0 <= p && p < _n);
return d[p + size];
}
S prod(int l, int r) {
assert(0 <= l && l <= r && r <= _n);
S sml = e(), smr = e();
l += size;
r += size;
while (l < r) {
if (l & 1) sml = op(sml, d[l++]);
if (r & 1) smr = op(d[--r], smr);
l >>= 1;
r >>= 1;
}
return op(sml, smr);
}
S all_prod() { return d[1]; }
template <bool (*f)(S)> int max_right(int l) {
return max_right(l, [](S x) { return f(x); });
}
template <class F> int max_right(int l, F f) {
assert(0 <= l && l <= _n);
assert(f(e()));
if (l == _n) return _n;
l += size;
S sm = e();
do {
while (l % 2 == 0) l >>= 1;
if (!f(op(sm, d[l]))) {
while (l < size) {
l = (2 * l);
if (f(op(sm, d[l]))) {
sm = op(sm, d[l]);
l++;
}
}
return l - size;
}
sm = op(sm, d[l]);
l++;
} while ((l & -l) != l);
return _n;
}
template <bool (*f)(S)> int min_left(int r) {
return min_left(r, [](S x) { return f(x); });
}
template <class F> int min_left(int r, F f) {
assert(0 <= r && r <= _n);
assert(f(e()));
if (r == 0) return 0;
r += size;
S sm = e();
do {
r--;
while (r > 1 && (r % 2)) r >>= 1;
if (!f(op(d[r], sm))) {
while (r < size) {
r = (2 * r + 1);
if (f(op(d[r], sm))) {
sm = op(d[r], sm);
r--;
}
}
return r + 1 - size;
}
sm = op(d[r], sm);
} while ((r & -r) != r);
return 0;
}
private:
int _n, size, log;
std::vector<S> d;
void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
};
using S=int;
S op(S l,S r){return l+r;}
S e(){return 0;}
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
const int mod=998244353;
const int base[]={12321,32123};
const double EPS=1e-9;
const double pi=acos(-1);
const int INF=1e18;
const int N=100017;
mt19937 rng(1235);
int n,q;
int p[N];
int ans[N],C[N],now[N];
vector<pii> info[N];
int st[N];
int lowbit(int u){return u&(-u);}
void update(int u,int w){for (int i=u;i<=n+7;i+=lowbit(i)) C[i]+=w;}
int query(int u){int ans=0; for (int i=u;i;i-=lowbit(i)) ans+=C[i]; return ans;}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int _;
cin>>_;
//_=1;
while (_--){
cin>>n>>q;
rep(i,n) cin>>p[i];
for (int i=1;i<=n+5;++i) C[i]=0,now[i]=0;
rep(i,N) info[i].clear();
p[n]=n+1;
rep(i,q){
int u,v;
cin>>u>>v;
u--, v--;
info[u].pb({i,v});
}
int cnt=0;
st[cnt++]=n;
auto upd=[&](int u){
update(u+1,(now[u+1]?-1:1)), now[u+1]^=1;
update(u+2,(now[u+2]?-1:1)), now[u+2]^=1;
};
for (int i=n-1;i>-1;--i){
while (cnt&&p[i]>p[st[cnt-1]]) {
cnt--; upd(st[cnt]);
}
st[cnt++]=i, upd(i);
for (auto c:info[i]){
int id=c.F, r=c.S;
if (i==r) ans[id]=0;
else ans[id]=(query(r+1)-query(i))/2;
}
}
rep(i,q) cout<<ans[i]<<"\n";
}
return 0;
}
Problem A. Arithmetic Subsequence、
题解:
首先如果某个数出现次数大于等于3则不存在解。然后如果所有数字均为偶数,我们
可将所有数除以二;如果所有数字均为奇数,我们可将所有数减去一;否则,我们将所有奇数放在
左边,所有偶数放在右边,对奇数/偶数分治解决。
代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
#include<stack>
#define int long long
#define double long double
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 5e3 + 10;
const int mod = 998244353;
int n;
vector<int> ans;
void solve()
{
cin >> n;
vector<int> a(n, 0);
ans.clear();
map<int, int> cnt;
for(int i = 0; i < n; i ++) cin >> a[i];
for(int i = 0; i < n; i++){
cnt[a[i]] ++;
if(cnt[a[i]] >= 3) {
cout << "NO\n";
return;
}
}
cout << "YES\n";
vector<pair<int, int>> v;
for(int i = 0; i < n; i++){
v.push_back({0, a[i]});
for(int j = 0; j < 30; j ++){
if(a[i] >> j & 1) v[i].first |= (1ll << (29 - j));
}
}
sort(begin(v), end(v));
for(int i = 0; i < n; i ++) ans.push_back(v[i].second);
for(auto re : ans) cout << re << ' ';
cout << '\n';
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int t = 1;
cin >> t;
while(t--){
solve();
}
}