若两个区间有交,显然可以把两个区间的值,都取在区间交集的端点的其中一个,
若没有交集的话,[l1,r1]<[l2,r2]时,取到r1和l2,也在区间的端点
因此,[l,r]的数,只由两端点决定,二选一,树形dp
#include
using namespace std;
#define pb push_back
typedef long long ll;
const int N=1e5+10;
int t,n,u,v;
vectorE[N];
ll dp[N][2],a[N][2];
void dfs(int u,int fa)
{
for(int i=0;i
赛后补题,
第一次操作,(a,b+(b-a))或(a+(a-b),b),要么前项加(a-b),要么后项加(b-a)
第二次操作,要么前项加2*(a-b),要么后项加2*(b-a)
第三次操作,要么前项加4*(a-b),要么后项加4*(b-a)
所以,c-a必须是a-b的倍数,d-b必须是a-b的倍数
特判a=b的情形,再讨论x=(c-a)/(a-b)和y=(d-b)/(a-b),显然答案唯一,与字典序无关
x和y非负且不能有交集,且x与y的并集构成二进制形如000001111111111的序列
#include
using namespace std;
typedef long long ll;
int t;
ll a,b,c,d,x,y;
bool ok(ll x)//判断x是否形如000111111 右起一段连续的1
{
x++;
x-=x&-x;
return x==0;
}
int main()
{
scanf("%d",&t);
while(t--)
{
//每次操作 必a+=k*(a-b) 或b+=k*(b-a) k为2的幂次且从1起不断*2
scanf("%lld%lld%lld%lld",&a,&b,&c,&d);//c-a=x*(a-b) d-b=y*(b-a) x和y二进制无交集
if(a==b)//c和d不会改变
{
if(c==a&&d==b)printf("Yes\n\n");
else puts("No");
continue;
}
if((c-a)%(a-b)||(d-b)%(b-a))
{
puts("No");
continue;
}
x=(c-a)/(a-b);y=(d-b)/(b-a);
if(x<0||y<0||(x&y)||!ok(x|y))
{
puts("No");
continue;
}
puts("Yes");
for(int i=0;(x>>i&1)|(y>>i&1);i++)
{
if(x>>i&1)putchar('B');
else putchar('A');
}
puts("");
}
return 0;
}
赛中AC,纪念一下
对于一棵子树来讲,其值一定是连续的,
所以子树值一定会被分成三段,[l,x],x+1,[x+2,r]
op[u]=0代表这棵子树中值最小的值出现在左子树,
op[u]=1代表出现在右子树
op[u]=2代表出现在根,根的时候分左子和右子的数量来讨论
数量相等时,再分左子和右子的最小值哪个小来讨论
#include
#include
#include
#include