Enlace del título
No escribiré las primeras tres preguntas sobre el agua.
D. Asignación de peso de borde
Tema: le da un árbol que requiere que asigne valores para cada borde
Practica
A primera vista, esta pregunta es encontrar una conclusión, solo empujar unos cuantos árboles más y empujarlo.
Conclusión: la mejor estructura, cada peso de borde es diferente. Debido a que el poder lateral es infinito, debe haber algún esquema legal para hacer que el poder lateral sea XOR 0
Si la distancia entre dos nodos de hoja es igual a 2, la respuesta es uno menos
dfs construye los puntos con múltiples nodos hoja menos:
5-2 == 3
Entonces, ¿cómo construir el mínimo?
En el caso más pequeño, solo hay dos casos, 1 o 3
Cuando la distancia de todos los nodos de las hojas es par (el peso del borde es 1), todos los pesos de los bordes pueden ser iguales. La respuesta es 1
Cuando hay un nodo hoja, la distancia es 3
En cuanto a cómo encontrar que la distancia entre una hoja es un número impar, usé un dp para cambiar la raíz
#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. Triples perfectos
Tema: necesita construir un triplete de pequeño a grande y cada número es único y a ^ b ^ c = 0 está conectado a la parte posterior de la secuencia s en secuencia, ingrese n para averiguar cuál es el enésimo número
Práctica: escuche a los amigos del grupo decir que XOR y el cuaternario son buenos hermanos. Escriba la tabla según el título:
Programa de mesa de juego:
#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; } } }
Parece que no hay regularidad
Cambiar a aspecto cuaternario:
Divida cada párrafo de acuerdo con la 4ª línea de alimentación:
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
Encontré vagamente una regla, cada bit del triplete en cada segmento es 0 1 2 3 cambios, y el número de 0 1 2 3 consecutivos con el 4 actual
El número de decimales.
El segundo número de triples es 0 2 3 1 cambio.
El tercer número del triple es el cambio de 0 3 1 2.
Las reglas están ahí, pero parece muy problemático construir
También es problemático hablar y estudiar el código directamente:
Código de referencia de: código fuente
Primero encuentre que el número p del n actual está en una fila p de cierto segmento del triple y el primer elemento de la primera fila del segmento actual:
ll p=(n-1)/3,s=1,all=0; while(p>=s) { p-=s; s<<=2; }
Según n% 3, encuentra el número en el triple.
En resumen: una muy buena regla y un muy buen método de construcción. .
#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;
}