E. Vlad and a Pair of Numbers
思路:
1,a^b==x==(a+b)/2==( (a+b)>>1 ),从二进制的角度,只要x第第i位x[i]=1,则b[i]或者a[i]必是一个1一个0。为了方便构造,我们可以把x有1的部分都给a
2,(x<<1)==(a+b),我们当前的a是x,b是0,那么我们设法修改a,b使其相加的值为x左移一位。
因为我们要保证a^b结果不变,所以修改a[i]与 b[i]只能同时为1,或者同时为0。
如果(x<<1)的第i位是1,即a的第i-1位是1,我们要使其左移,可以修改a[i-2]=1,b[i-2]=1,前提是a[i-2]与b[i-2]原本是0。即x是不能有连续的1存在的,否则构造不出a,b。
3,如果可以构造出,会发现,a的每个1后面都会加上1,那么其实整体就是加上x>>1,所以a=x+x>>1,b=x>>1。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
typedef unsigned long long ull;
typedef pair<long long, long long> pll;
typedef pair<int, int> pii;
//double 型memset最大127,最小128
//std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
const int INF = 0x3f3f3f3f; //int型的INF
const ll llINF = 0x3f3f3f3f3f3f3f3f;//ll型的llINF
const int N = 2e5 + 10;
void msolve()
{
int x;
cin >> x;
if (x & 1)//x奇数显然无法构造
{
cout << -1 << endl;
return;
}
else
{
int k = x >> 1;
if ((k & x))//合法的构造即x必须没有连续的1,这样的他与右移一位的自己&得出是0,否则就一定不是0
{
cout << -1 << endl;//不是0说明无法构造
return ;
}
cout << x / 2 * 3 << ' ' << x / 2 << endl;
}
}
int main()
{
int t;
cin >> t;
while (t--)
{
msolve();
}
return 0;
}
F. Timofey and Black-White Tree
思路:
就是数上跑最短路,重点优化就是不去跑已经大于答案的点。
1,我们用dis[i]表示从i点出发到达任意黑点的最短距离(i自己可以不用是黑点)。
2,显然,在不断更新中,我们一直都使所有dis[i]都表示到任意黑点最短距离,当我们把i变为黑点时,dis[i]就变为这个黑点与所有黑点中的最短距离
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
#define endll endl<<endl
typedef unsigned long long ull;
typedef pair<long long, long long> pll;
//---------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------//
const int INF = 0x3f3f3f3f; //int型的INF
const ll llINF = 0x3f3f3f3f3f3f3f3f;//ll型的llINF
const int N = 2e5 + 100;
int head[N << 1], dis[N], c[N];
int num;
int n;
int ans;
struct node
{
int next, to;
} edge[N << 1];
void add(int u, int v)
{
edge[++num].next = head[u];
edge[num].to = v;
head[u] = num;
}
void init()
{
memset(head, 0, sizeof(head));
memset(dis, 0x3f, sizeof(dis));
num = 0;
ans = INF;
}
void dijksta(int k)
{
queue<int>q;
q.push(k);
ans = min(ans, dis[k]);//当把k设立为黑点,dis[k]表示一个黑点间距离,与ans取min
dis[k] = 0;//然后我们以这个k黑点为起点,更新其他点到他的距离(如果到k的距离比那个点到已有黑点距离小的话)
while (!q.empty())
{
int u = q.front();
q.pop();
if (dis[u] + 1 >= ans)continue;//核心剪枝,如果大于目前答案,无需继续深入
for (int i = head[u]; i; i = edge[i].next)
{
int v = edge[i].to;
if (dis[v] > dis[u] + 1)//到u这个黑点距离小,更新
{
dis[v] = dis[u] + 1;
q.push(v);
}
}
}
}
void mysolve()
{
cin >> n;
init();
int u, v;
for (int i = 1; i <= n; ++i)cin >> c[i];
for (int i = 1; i < n; ++i)
{
cin >> u >> v;
add(u, v);
add(v, u);
}
for (int i = 1; i <= n; ++i)//i==1,只是建立c0,铺设所有点都源点的最短距离
{
dijksta(c[i]);
if (i > 1)
{
cout << ans;
if (i == n)cout << endl;
else cout << ' ';
}
}
}
int32_t main()
{
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll t;
cin >> t;
while (t--)
{
mysolve();
}
system("pause");
return 0;
}