Title link
I will not write the first three questions for water questions (water questions have been done for so long and I was awakened by myself)
D. Edge Weight Assignment
Topic: Give you a tree that requires you to assign values for each edge
practice:
At first glance, this question is to find a conclusion, just push a few more trees and push it.
Conclusion: The best structure, each edge weight is different. Because the side power is infinite, there must be some legal scheme to make the side power XOR 0
If the distance between two leaf nodes is equal to 2, the answer is one less
dfs constructs the points with multiple leaf nodes minus:
5-2==3
So how to construct the minimum?
In the smallest case, there are only two cases, either 1 or 3
When the distance of all leaf nodes is even (edge weight is 1), all edge weights can be equal. The answer is 1
When there is a leaf node the distance is 3
As for how to find the distance between a leaf is an odd number, I used the root dp, there are many ways
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e5+10;
int dp[N][2],n;
vector<int>G[N];
int mi,mx,du[N],root;
void dfs1(int u,int fa)
{
if(du[u]==1){
dp[u][0]++;
return ;
}
for(int v:G[u])
{
if(v==fa) continue;
dfs1(v,u);
dp[u][1]+=dp[v][0];
dp[u][0]+=dp[v][1];
}
}
void dfs2(int u,int fa)
{
if(du[u]==1&&dp[u][1]) {
mi=3;
//printf("u:%d\n",u);
}
if(mi!=1) return ;
for(int v:G[u])
{
if(v==fa) continue;
int t0=dp[u][0];
int t1=dp[u][1];
dp[u][0]-=dp[v][1];
dp[u][1]-=dp[v][0];
dp[v][0]+=dp[u][1];
dp[v][1]+=dp[u][0];
dfs2(v,u);
dp[u][0]=t0;
dp[u][1]=t1;
}
}
int dfs3(int u,int fa)
{
int flag=0;
for(int v:G[u])
{
if(v==fa) continue;
flag+=dfs3(v,u);
}
if(flag>=2) mx-=flag-1;
if(du[u]==1) return 1;
return 0;
}
int main()
{
cin>>n;
rep(i,2,n)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
du[u]++;
du[v]++;
}
rep(i,1,n) if(du[i]>=2) root=i;
dfs1(root,-1);
mi=1;
dfs2(root,-1);
mx=n-1;
dfs3(root,-1);
printf("%d %d\n",mi,mx);
}
E. Perfect Triples
Topic: You need to construct a triplet from small to large and each number is unique and a ^ b ^ c = 0 is connected to the back of the sequence s in sequence, enter n to find out what the nth number is
Practice: Listen to group friends say XOR and quaternary are good brothers. Type the table according to the title:
Playing table program:
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=(b);++i) #define mem(a,x) memset(a,x,sizeof(a)) #define pb push_back #define pi pair<int, int> #define mk make_pair using namespace std; typedef long long ll; ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;} const int N=1e5+10; int vis[N]; void cal(int x) { stack<int>sta; while(x) { int d=x%4; sta.push(d); x=x/4; } while(sta.size()) { printf("%d",sta.top()); sta.pop(); } printf(" "); } int main() { rep(i,1,200) rep(j,1,200) rep(k,1,200){ if(vis[i]||vis[j]||vis[k]) continue; if((i^j^k)==0){ //cal(i),cal(j),cal(k); //puts(""); printf("%d %d %d\n",i,j,k); vis[i]=1,vis[j]=1,vis[k]=1; } } }
There seems to be no regularity
Change to quaternary look:
Divide each paragraph according to the 4 ^ th power line:
1 2 3 10 20 30 11 22 33 12 23 31 13 21 32 100 200 300 101 202 303 102 203 301 103 201 302 110 220 330 111 222 333 112 223 331 113 221 332 120 230 310 121 232 313 122 233 311 123 231 312 130 210 320 131 212 323 132 213 321 133 211 322 1000 2000 3000 1001 2002 3003 1002 2003 3001 1003 2001 3002 1010 2030 3020 1020 2031 3011 1021 2032 3013 1023 2033 3010 1030 2022 3012
I vaguely found a rule, each bit of the triplet in each segment is 0 1 2 3 changes, and the number of 0 1 2 3 consecutive with the current 4
The number of decimal places.
The second number of triples is 0 2 3 1 change.
The third number of the triple is the change of 0 3 1 2.
The rules are there, but it seems very troublesome to construct
It's also troublesome to talk about, and study the code directly:
Code reference from: code source
First find out the number p of the current n is in a row p of a certain segment of the triple and the first element of the first row of the current segment:
ll p=(n-1)/3,s=1,all=0; while(p>=s) { p-=s; s<<=2; }
According to n% 3, find the number in the triple.
In summary: a very good rule and a very good construction method. .
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int _;cin>>_;while(_--)
{
ll n;
cin>>n;
ll p=(n-1)/3,s=1,all=0;
//当前n处在三元组 某一段中 某一行p 当前段第一行 第一个元素 的数字s:
while(p>=s)
{
p-=s;
s<<=2;
}
//p行对应的进制变化分别是0,1,2,3 0 2 3 1 0 3 2 1
if(n%3==1) printf("%lld\n",s+p);//第一个数直接加
else if(n%3==2)//第二个
{
ll ans=s<<1,c=1;//每一段的第一行是特殊的 x 2*x 3*x
while(p)
{
//四进制的最低位
ll x=p%4;
if(x==1) ans+=c*2;
else if(x==2) ans+=c*3;
else if(x==3) ans+=c;
p>>=2,c<<=2;
}
printf("%lld\n",ans);
}
else
{
ll ans=s*3,c=1;
while(p)
{
ll x=p%4;
if(x==1) ans+=c*3;
else if(x==2) ans+=c*1;
else if(x==3) ans+=c*2;
p>>=2,c<<=2;
}
printf("%lld\n",ans);
}
}
return 0;
}