コンテストリンク:https : //codeforces.com/contest/1338
A.パワードアディション
補題:正の整数\(a \)は\([a、a + 2 ^ k-1] \)内で\(k \)秒以内に任意の数値に変換できます
それは最終的に非減少シーケンスになるので、(各要素の最小パディング量)\(S \)の最大値を取るだけでよいので、\(S \)より大きい2の最小整数乗は\(2 ^ k \ )、補題によると、答えは\(k \) qwqです
#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
const int N=200010; typedef long long ll; const int inf=~0u>>2; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
#define int ll
int a[N];
int ans,n;
signed main(){
int T; cin>>T;
while(T--){
cin>>n;
repeat(i,0,n)cin>>a[i];
int x=-inf;
ans=0;
repeat(i,0,n){
if(a[i]<x)ans=max(ans,x-a[i]);
x=max(x,a[i]);
}
int cnt=0;
while(ans)ans>>=1,cnt++;
cout<<cnt<<endl;
}
return 0;
}
B.エッジの重みの割り当て
ちょっとしたトリックは、2つのノード間のパスのxor合計です。つまり、パスxorと2つのノードからルートへのパスのxor合計です。
次数が1のノードをルートとします。利点は、2つのリーフのパスを確認する必要がないことです。ルートへのすべての葉のxor合計が0であることを確認するだけです(ヒントによると)。
最初のサブタスクは非常に単純です。答えは1または3のみで、2つのケースに分けられます(ルート次数が1かどうかを確認してください)
根の次数が1の場合、すべての葉の深さが均一で、答えは1です。
ルートの次数が1でない場合、すべての葉の深さのパリティは同じで、答えは1です。
2番目のサブタスクに関しては、1つの操作が激しくなった後、ほとんどの場合、2つのエッジの重みが等しくないことがわかりますが、多くのリーフがノードに接続されている場合、これらのエッジのエッジの重みは強制的に等しくされ、減算するだけです。できる
また、次数1のノードを根とする場合は、もともと葉であるため特別な判断が必要で、それ以外は特別な判断は不要です。
ここでは、次数1のノードをルートとしました
#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
const int N=200010; typedef long long ll; const int inf=~0u>>2; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
//#define int ll
vector<int> a[N];
int rt,ans;
int deg[N],cnt[N],depth[N];
int flag=true;
void dfs(int x,int fa){
for(auto p:a[x])
if(p!=fa){
depth[p]=depth[x]+1;
dfs(p,x);
cnt[x]+=deg[p]==1;
}
if(deg[x]==1 && depth[x]%2==1)flag=false;
if(depth[x]==1)ans-=cnt[x];
else ans-=max(cnt[x]-1,0);
}
signed main(){
int n=read();
repeat(i,0,n-1){
int x=read()-1,y=read()-1;
a[x].push_back(y); a[y].push_back(x);
deg[x]++,deg[y]++;
}
repeat(i,0,n){
if(deg[i]==1){rt=i; break;}
}
dfs(rt,-1);
ans+=n-1;
cout<<(flag?1:3)<<' '<<ans<<endl;
return 0;
}
C.パーフェクトトリプル
最初にいくつか(バイナリ)をリストします
1 10 11
100 1000 1100
101 1010 1111
110 1011 1101
111 1001 1110
10000 100000 110000
10001 100010 110011
10010 100011 110001
10011 100001 110010
10100 101010 111110
...
何を見つけましたか?
そうです、私はそれを0231法則(霧)と呼びます。つまり、最初の列の数が決定された場合、2番目の列の数は次の方法で取得できます。最初に16進数に変換され、次に\([0,1,2 、3] \)は対応して\([0,2,3,1] \)になります
完璧です。最初の列の数は非常に規則的(多くの連続)で、3番目の列の数は最初の列xまたは 2番目の列によって取得されるため、水のタイトルは実際にはdiv1C、霧の位置に配置されます。
変数名を取得するのは本当に難しいので、スパイシーなチキンコードが警告します
#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
const int N=200010; typedef long long ll; const int inf=~0u>>2; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
#define int ll
int ss[4]={0,2,3,1};
int f(int x){
if(x==0)return 0;
return f(x/4)*4+ss[x%4];
}
signed main(){
int T=read();
while(T--){
int n=read()-1; if(n<3){cout<<n+1<<endl; continue;}
int p=n/3;
int x;
for(x=1;p>=0;p-=x,x*=4);
x/=4; p+=x;
if(n%3==0){cout<<p+x<<endl; continue;}
int t1=x+p;
int t2=f(t1);
if(n%3==1)cout<<t2<<endl;
else cout<<(t1^t2)<<endl;
}
return 0;
}