CF1665
CF1665
GCD vs LCM
简单构造 我们让
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define pii pair<int,int>
#define fi first
#define se second
#define getchar() cin.get()
#define int long long
const int N = 3e5 + 5;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
n = read();
cout << "1 " << n - 3 << " 1 1" << endl;
}
return 0;
}
Array Cloning Technique
可能是不太一样的做法(?)
我们稍微手推一下可以发现 一定要使得原数组中出现次数最多的一个数成为最终数组中的数(可以用
那么最优策略是先复制出来一组数 再将所有数合并到一起 如果还是不能覆盖全部数组 那么我们将这个合并之后的数组再复制出来一份继续进行上述操作即可
考虑模拟 我们设最多出现数的次数为
设
最后将复制次数和移动次数(
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define pii pair<int,int>
#define fi first
#define se second
#define getchar() cin.get()
#define int long long
const int N = 3e5 + 5;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , a[N] , cnt;
map<int,int> mp;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
n = read();
mp.clear() , cnt = 0;
for ( int i = 1 ; i <= n ; i ++ ) mp[a[i]=read()] ++;
for ( int i = 1 ; i <= n ; i ++ ) cnt = max ( mp[a[i]] , cnt );
int res = 0 , stp = 0 , temp = cnt;
while ( res < n - cnt )
{
++ stp;
res += temp;
temp <<= 1;
}
cout << stp + n - cnt << endl;
}
return 0;
}
Tree Infection
因为题目中说一个点只能传染给它的兄弟节点 也就是说树上每一层节点都是独立的
考虑我们第一轮感染一定是从最多的节点向最少的节点来感染 (所有儿子数量为
那么考虑第二轮感染 我们显然不能一直感染最大的那个节点 例如有一个
所以我们开一个堆记录剩余的健康节点个数的最大值 每次拎出来这个最大值并注射这个节点即可
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define pii pair<int,int>
#define fi first
#define se second
#define getchar() cin.get()
#define int long long
const int N = 2e5 + 5;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , cnt[N];
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
n = read();
fill ( cnt + 1 , cnt + n + 1 , 0 );
for ( int i = 1 ; i < n ; i ++ ) cnt[read()] ++;
cnt[0] = 1;
sort ( cnt , cnt + n + 1 );
for ( int i = 0 ; i <= n ; i ++ )
if ( cnt[i] != 0 )
{
priority_queue<int> q;
for ( int j = i ; j <= n ; j ++ ) q.push ( cnt[j] - ( j - i + 1 ) );
int spread = 0 , ans = n - i + 1;
while ( q.top() > spread )
{
int x = q.top(); q.pop();
q.push ( x - 1 ) , ++ spread , ++ ans;
}
cout << ans << endl;
break;
}
}
return 0;
}
GCD Guess
根据更相减损术 可以得到
因为最多询问
我们从低位向高位猜 假设我们现在猜的是从右到左第
那么我们设
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define ls p<<1
#define rs p<<1|1
#define mid (l+(r-l>>1))
#define pii pair<int,int>
#define lson ls,l,mid
#define rson rs,mid+1,r
#define fi first
#define se second
#define getchar() cin.get()
#define print(x) cout<<#x<<'='<<x<<endl
const int inf = INT_MAX;
const int N = 2e5 + 5;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , a[N] , q , s[N];
int query ( int x , int y )
{
cout << "? " << x << ' ' << y << endl << flush;
return read();
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int TT = read();
while ( TT -- )
{
int x = 0;
for ( int i = 1 ; i <= 30 ; i ++ )
{
int res = query ( ( 1 << i - 1 ) - x , ( 1 << i ) + ( 1 << i - 1 ) - x );
if ( res & ( 1 << i ) ) x |= 1 << i - 1;
}
cout << "! " << x << endl << flush;
}
return 0;
}
MinimizOR
一个结论:区间内的最小代价为区间内的前
证明:采用数学归纳法 原命题等价于小于
也就是说如果区间中每一个数都小于
对于
那么对于
-
如果序列中最高位的数中
个 高位贪心 那么或起来 当前位一定选 最小值一定出现在 位的最小值 那么根据 的结论 一定出现在前 小中 -
如果有
个 那么或起来当前位置一定为 那么最小值一定是在前 个最高位为 的最小值 和那一个最高位为 的值之间选取那么一定在前
中选取 -
如果没有
那么只能选 类似第一种情况 结果一定是 位中的最小值 那么根据 的结论 一定在前 小中
用线段树暴力提取区间前
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define ls p<<1
#define rs p<<1|1
#define mid (l+(r-l>>1))
#define pii pair<int,int>
#define lson ls,l,mid
#define rson rs,mid+1,r
#define fi first
#define se second
#define getchar() cin.get()
#define print(x) cout<<#x<<'='<<x<<endl
const int inf = INT_MAX;
const int N = 2e5 + 5;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , a[N] , q , s[N];
struct Tree
{
pii t[N<<2];
inl void up ( int p ) { t[p] = min ( t[ls] , t[rs] ); }
void build ( int p , int l , int r )
{
if ( l == r ) return t[p] = { a[l] , l } , void();
build ( lson ) , build ( rson ) , up(p);
}
void upd ( int p , int l , int r , int x , int val )
{
if ( l == r ) return t[p] = { val , l } , void();
if ( x <= mid ) upd ( lson , x , val );
else upd ( rson , x , val );
up(p);
}
pii query ( int p , int l , int r , int x , int y )
{
if ( x <= l && r <= y ) return t[p];
pii res = { inf , inf };
if ( x <= mid ) res = min ( res , query ( lson , x , y ) );
if ( mid + 1 <= y ) res = min ( res , query ( rson , x , y ) );
return res;
}
}T;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int TT = read();
while ( TT -- )
{
n = read();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
T.build ( 1 , 1 , n );
q = read();
for ( int i = 1 ; i <= q ; i ++ )
{
int l = read() , r = read() , ans = inf , tot = min ( r - l + 1 , 31 );
for ( int j = 1 ; j <= tot ; j ++ )
{
s[j] = T.query ( 1 , 1 , n , l , r ).se;
T.upd ( 1 , 1 , n , s[j] , inf );
}
for ( int j = 1 ; j <= tot ; j ++ ) T.upd ( 1 , 1 , n , s[j] , a[s[j]] );
for ( int j = 1 ; j <= tot ; j ++ )
for ( int k = j + 1 ; k <= tot ; k ++ )
ans = min ( ans , a[s[j]] | a[s[k]] );
cout << ans << endl;
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!