1. GUI
按题意判断即可。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 0, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
bool inclu(int L, int R, int l, int r)
{
return L <= l && r <= R;
}
int main()
{
scanf("%d", &casenum);
for (casei = 1; casei <= casenum; ++casei)
{
int x1, x2, x3, x4;
int y1, y2, y3, y4;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
scanf("%d%d%d%d",&x3,&y3,&x4,&y4);
if(inclu(x1,x2,x3,x4) && inclu(y1,y2,y3,y4))
{
puts("B in A");
}
else if(inclu(x3,x4,x1,x2) && inclu(y3,y4,y1,y2))
{
puts("A in B");
}
else if((x2 < x3 || x4 < x1) || (y2 < y3 || y4 < y1))
{
puts("Separate");
}
else puts("Intersect");
}
return 0;
}
/*
【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 */
2. Searching on the Cube
首先爬山找到一个极小点,然后不断前进找到另一个极小点,分析哪一个是答案即可。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 0, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n;
char rtn[100];
void fwd()
{
puts("forward");
fflush(stdout);
scanf("%s", rtn);
}
void rgt()
{
puts("right");
fflush(stdout);
}
void lft()
{
puts("left");
fflush(stdout);
}
void dig()
{
puts("dig");
fflush(stdout);
exit(0);
}
bool BEST()
{
fwd();
if(strcmp(rtn, "closer") == 0)
{
return 0;
}
lft(); lft(); fwd();
fwd();
if(strcmp(rtn, "closer") == 0)
{
return 0;
}
lft(); lft(); fwd();
lft(); fwd();
if(strcmp(rtn, "closer") == 0)
{
return 0;
}
lft(); lft(); fwd();
fwd();
if(strcmp(rtn, "closer") == 0)
{
return 0;
}
lft(); lft(); fwd();
return 1;
}
bool onlycheckBEST()
{
bool flag = 1;
fwd();
if(strcmp(rtn, "closer") == 0)
{
flag = 0;
}
lft(); lft(); fwd(); lft(); lft();
if(!flag)return 0; lft(); fwd();
if(strcmp(rtn, "closer") == 0)
{
flag = 0;
}
lft(); lft(); fwd(); lft();
if(!flag)return 0; rgt(); fwd();
if(strcmp(rtn, "closer") == 0)
{
flag = 0;
}
lft(); lft(); fwd(); rgt();
if(!flag)return 0; lft(); lft(); fwd();
if(strcmp(rtn, "closer") == 0)
{
flag = 0;
}
lft(); lft(); fwd();
if(!flag)return 0;
return 1;
}
int main()
{
while(!BEST());
int clo = 0;
int far = 0;
while(1)
{
fwd();
if(strcmp(rtn, "closer") == 0)
{
++clo;
}
else if(strcmp(rtn, "farther") == 0)
{
++far;
}
if(onlycheckBEST())
{
if(clo >= far)
{
dig();
}
else clo = far = 0;
}
}
return 0;
} /*
【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 */
3. Mirrors
留坑。
4. Roads to cinematography
$1$和$n$的最优连法一定是$1$往下,$n$往左,中间必然存在一个点$i$满足$i$往左到$1$,$i+1$往下到$n$。
设$f[l][r]$表示$l$往下,$r$往左时,$[l,r]$的最优连法,枚举$i$转移即可。
时间复杂度$O(n^3)$。
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=505,inf=1000000000;
int n,i,j,m,e[100010][4];
int f[N][N],g[N][N];bool v[N][N];
struct P{int x,y;}a[N];
inline void add(int x1,int y1,int x2,int y2){
if(x1<x2)swap(x1,x2),swap(y1,y2);
if(y1<y2)swap(x1,x2),swap(y1,y2);
if(x1==x2&&y1==y2)return;
m++;
e[m][0]=x1;
e[m][1]=y1;
e[m][2]=x2;
e[m][3]=y2;
}
void dfs(int l,int r){
if(l+1>=r)return;
if(v[l][r])return;
v[l][r]=1;
f[l][r]=inf;
for(int i=l;i<r;i++){
//i left,i+1 down
dfs(l,i);
dfs(i+1,r);
int t=f[l][i]+f[i+1][r]+a[i].x-a[l].x+a[i+1].y-a[r].y;
if(t<f[l][r]){
f[l][r]=t;
g[l][r]=i;
}
}
}
void go(int l,int r){
if(l+1>=r)return;
int i=g[l][r];
go(l,i);
go(i+1,r);
add(a[l].x,a[i].y,a[i].x,a[i].y);
add(a[i+1].x,a[r].y,a[i+1].x,a[i+1].y);
}
int main(){
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d%d",&a[i].x,&a[i].y);
dfs(1,n);
f[1][n]+=a[1].x+a[1].y+a[n].x-a[1].x;
add(0,0,a[1].x,0);
add(a[1].x,0,a[1].x,a[1].y);
add(a[1].x,a[n].y,a[n].x,a[n].y);
go(1,n);
printf("%d %d\n",m,f[1][n]);
for(i=1;i<=m;i++){for(j=0;j<4;j++)printf("%d ",e[i][j]);puts("");}
}
5. Geometric solver
按题意模拟。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 2e5 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n, m;
int id[N];
int root[N];
int col[N];
bool edge[N];
vector<int>ans;
bool FLAG;
struct A
{
int y;
int tp;
int id;
};
vector< A >a[N];
void dfs(int x)
{
for(auto it : a[x])
{
int y = it.y;
int tp = it.tp;
int id = it.id;
if(col[y] == -1)
{
col[y] = col[x] ^ tp;
edge[id] = 1;
dfs(y);
}
else
{
if(!edge[id])
{
edge[id] = 1;
ans.push_back(it.id);
//printf("!edge[id]: %d\n", id);
}
if(col[y] != (col[x] ^ tp))
{
FLAG = 0;
}
}
}
}
int main()
{
while(~scanf("%d%d",&n, &m))
{
MS(edge, 0);
MS(root, -1);
MS(id, -1);
ans.clear();
for(int i = 1; i <= n; ++i)
{
a[i].clear();
}
FLAG = 1;
for(int i = 1; i <= m; ++i)
{
char op[100];
scanf("%s", op);
if(op[0] == 'v')
{
int x; scanf("%d", &x);
if(root[x] == 0)
{
ans.push_back(i);
//printf("root[x] == 0: %d\n", i);
}
else if(root[x] == 1)
{
FLAG = 0;
}
else
{
root[x] = 0;
id[x] = i;
}
}
else if(op[0] == 'h')
{
int x; scanf("%d", &x);
if(root[x] == 1)
{
ans.push_back(i);
//printf("root[x] == 1: %d\n", i);
}
else if(root[x] == 0)
{
FLAG = 0;
}
else
{
root[x] = 1;
id[x] = i;
}
}
else
{
int x, y;
scanf("%d%d", &x, &y);
if(op[1] == 'e')//be horizontal
{
a[x].push_back({y, 1, i});
a[y].push_back({x, 1, i});
}
else
{
a[x].push_back({y, 0, i});
a[y].push_back({x, 0, i});
}
}
}
MS(col, -1);
int useful = 0;
for(int i = 1; i <= n; ++i)
{
if(root[i] != -1)
{
if(col[i] == -1)
{
col[i] = root[i];
dfs(i);
++useful;
}
else
{
if(col[i] != root[i])
{
FLAG = 0;
}
ans.push_back(id[i]);
//printf("same_con: %d\n", id[i]);
}
}
}
for(int i = 1; i <= n; ++i)
{
if(col[i] == -1)
{
col[i] = 0;
dfs(i);
}
}
if(!FLAG)
{
puts("inconsistent");
}
else
{
puts("consistent");
printf("%d\n", ans.size());
int sz = ans.size();
for(int i = 0; i < sz; ++i)
{
printf("%d%c", ans[i], i == sz - 1 ? '\n' : ' ');
}
}
}
return 0;
} /*
【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 */
6. Monsters
设$f[i]=\max(f[i-1],s[i])$,则$ans=\prod\min(m[i],f[i])$。
线段树维护每个区间$[l,r]$内只考虑区间$[l,r]$时以下信息:
- $fl,fr$:$f[l]$和$f[r]$的值。
- $mul$:$\prod\min(m[i],f[i])$。
- $rmul$:将右儿子用左儿子的$f$修正后右儿子的贡献。
对于$mul$,有$mul=左儿子的mul\times ask(右儿子,左儿子的f[r])$。
其中$ask(x,pre)$表示考虑$x$的子树,之前$f$为$pre$时的乘积:
- 若$fl\geq pre$,则无需修正,直接返回$mul$即可。
- 若$x$为叶子,则暴力处理即可。
- 若左儿子的$fr\geq pre$,则右儿子只会被左儿子修正,返回$ask(左儿子,pre)\times rmul$即可。
- 否则左儿子将全部被修正为$pre$,故返回$ask(右儿子,pre)\times 左儿子全部修正为pre$的贡献即可。而贡献可以在每个节点套上一棵Treap来$O(\log n)$计算。
总时间复杂度$O(n\log^3n)$。
#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int N=100010,M=262150,P=1000000007;
int fl[M],fr[M],mul[M],rmul[M];
int n,_,i,s[N],m[N];
int CNT,MUL,ni;
struct node{
int val,cnt,sum,v,mul,p;
node*l,*r;
node(){
val=cnt=sum=p=0;
v=mul=1;
l=r=NULL;
}
void up(){
sum=cnt+l->sum+r->sum;
mul=1LL*v*l->mul%P*r->mul%P;
}
}*blank=new(node),*T[M],pool[5000000],*cur=pool;
inline void Rotl(node*&x){node*y=x->r;x->r=y->l;x->up();y->l=x;y->up();x=y;}
inline void Rotr(node*&x){node*y=x->l;x->l=y->r;x->up();y->r=x;y->up();x=y;}
void Ins(node*&x,int p){
if(x==blank){
x=cur++;
x->val=p;
x->l=x->r=blank;
x->cnt=x->sum=1;
x->v=x->mul=p;
x->p=rand();
return;
}
x->sum++;
x->mul=1LL*x->mul*p%P;
if(p==x->val){
x->cnt++;
x->v=1LL*x->v*p%P;
return;
}
if(p<x->val){
Ins(x->l,p);
if(x->l->p>x->p)Rotr(x);
}else{
Ins(x->r,p);
if(x->r->p>x->p)Rotl(x);
}
}
void Del(node*&x,int p,int q){
x->sum--;
x->mul=1LL*x->mul*q%P;
if(p==x->val){
x->cnt--;
x->v=1LL*x->v*q%P;
return;
}
if(p<x->val){
Del(x->l,p,q);
if(x->l->p>x->p)Rotr(x);
}else{
Del(x->r,p,q);
if(x->r->p>x->p)Rotl(x);
}
}
void Ask(node*&x,int p){//<p
if(x==blank)return;
if(p==x->val){
CNT+=x->l->sum;
MUL=1LL*MUL*x->l->mul%P;
return;
}
if(p<x->val){
Ask(x->l,p);
return;
}
Ask(x->r,p);
CNT+=x->l->sum+x->cnt;
MUL=1LL*MUL*x->l->mul%P*x->v%P;
}
inline int po(int a,int b){
int t=1;
for(;b;b>>=1,a=1LL*a*a%P)if(b&1)t=1LL*t*a%P;
return t;
}
void build(int x,int a,int b){
if(a<b){
int mid=(a+b)>>1;
build(x<<1,a,mid);
build(x<<1|1,mid+1,b);
}
int i;
fl[x]=fr[x]=s[a];
mul[x]=1;
T[x]=blank;
for(i=a;i<=b;i++){
fr[x]=max(fr[x],s[i]);
mul[x]=1LL*mul[x]*min(fr[x],m[i])%P;
Ins(T[x],m[i]);
}
if(a<b)rmul[x]=1LL*mul[x]*po(mul[x<<1],P-2)%P;
}
inline int query(int x,int a,int b,int pre){
CNT=0;
MUL=1;
Ask(T[x],pre);
return 1LL*MUL*po(pre,b-a+1-CNT)%P;
//int t=1;
//for(int i=a;i<=b;i++)t=1LL*t*min(m[i],pre)%P;
//return t;
}
int ask(int x,int a,int b,int pre){
if(fl[x]>=pre)return mul[x];
if(a==b)return min(m[a],pre);
int mid=(a+b)>>1;
if(fr[x<<1]>=pre)return 1LL*ask(x<<1,a,mid,pre)*rmul[x]%P;
return 1LL*query(x<<1,a,mid,pre)*ask(x<<1|1,mid+1,b,pre)%P;
}
inline void up(int x,int a,int b){
fl[x]=fl[x<<1];
fr[x]=max(fr[x<<1],fr[x<<1|1]);
int mid=(a+b)>>1;
mul[x]=1LL*mul[x<<1]*ask(x<<1|1,mid+1,b,fr[x<<1])%P;
rmul[x]=1LL*mul[x]*po(mul[x<<1],P-2)%P;
}
void change(int x,int a,int b,int c){
if(a==b){
fl[x]=fr[x]=s[a];
mul[x]=min(s[a],m[a]);
return;
}
int mid=(a+b)>>1;
if(c<=mid)change(x<<1,a,mid,c);else change(x<<1|1,mid+1,b,c);
up(x,a,b);
}
void changem(int x,int a,int b,int c,int A,int B){
Ins(T[x],B);
Del(T[x],A,ni);
if(a==b)return;
int mid=(a+b)>>1;
if(c<=mid)changem(x<<1,a,mid,c,A,B);else changem(x<<1|1,mid+1,b,c,A,B);
}
int main(){
blank->l=blank->r=blank;
scanf("%d%d%d",&n,&_,&s[1]);
for(i=1;i<=n;i++)scanf("%d",&m[i]);
for(i=2;i<=n+1;i++)scanf("%d",&s[i]);
build(1,1,n);
//shutaoshu
printf("%d\n",mul[1]);
while(_--){
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(op==0){
ni=po(m[x],P-2);
changem(1,1,n,x,m[x],y);
m[x]=y;
change(1,1,n,x);
}else{
x++;
if(x<=n){
s[x]=y;
change(1,1,n,x);
}
}
printf("%d\n",mul[1]);
}
}
7. Regular expressions
注意到$((a(c|(g|t)))*)$可以匹配所有字符串,所以答案不超过$16$。
爆搜出所有短正则表达式后,建立DFA,最小化DFA判断即可。
8. WSO-2017 soccer team
假设所有人都选择$2a[i]$,那么需要选出$k=\frac{r-l+1}{3}$个人增加$2(d[i]-a[i])$,还需要再选出$k$个人增加$d[i]-a[i]$,故可持久化线段树维护区间$k$小值即可。
时间复杂度$O(n\log n)$。
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=129000,M=N*21;
int n,m,i,x,y;
ll a[N],d[N],sa[N],c[N];
int T[N],tot,l[M],r[M],cnt[M];ll sum[M];
int ins(int x,int a,int b,int c,ll p){
int y=++tot;
cnt[y]=cnt[x]+1;
sum[y]=sum[x]+p;
if(a==b)return y;
int mid=(a+b)>>1;
if(c<=mid)l[y]=ins(l[x],a,mid,c,p),r[y]=r[x];
else l[y]=l[x],r[y]=ins(r[x],mid+1,b,c,p);
return y;
}
inline ll kth(int x,int y,int k){
if(!k)return 0;
int a=1,b=n,mid;ll ans=0;
while(a<b){
mid=(a+b)>>1;
int t=cnt[l[x]]-cnt[l[y]];
if(t>=k){
b=mid;
x=l[x];
y=l[y];
}else{
k-=t;
ans+=sum[l[x]]-sum[l[y]];
a=mid+1;
x=r[x];
y=r[y];
}
}
if(k)ans+=(sum[x]-sum[y])/(cnt[x]-cnt[y])*k;
return ans;
}
inline ll ask(int x,int y,int l,int r){return kth(x,y,r)-kth(x,y,l-1);}
int main(){
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%lld",&a[i]),sa[i]=sa[i-1]+a[i];
for(i=1;i<=n;i++)scanf("%lld",&d[i]);
for(i=1;i<=n;i++)c[i]=d[i]-a[i];
sort(c+1,c+n+1);
for(i=1;i<=n;i++)T[i]=ins(T[i-1],1,n,lower_bound(c+1,c+n+1,d[i]-a[i])-c,d[i]-a[i]);
scanf("%d",&m);
while(m--){
scanf("%d%d",&x,&y);
ll ans=(sa[y]-sa[x-1])*2;
int len=(y-x+1)/3;
ans+=ask(T[y],T[x-1],len*2+1,len*3)*2;
ans+=ask(T[y],T[x-1],len+1,len*2);
printf("%lld.%lld\n",ans/2,ans%2*5);
}
}
9. Primitive divisors
枚举所有的质数$p$,满足$q^n\bmod p=1$的$p$不会很多,对于每个将$\varphi(p)$分解质因数找到最小循环节判断即可。
#include<cstdio>
const int N=10000000;
int n,q,tot,i,j,p[N],ans[N],fin,v[N];
inline int po(int a,int b,int P){
int t=1;
for(;b;b>>=1,a=1LL*a*a%P)if(b&1)t=1LL*t*a%P;
return t;
}
inline bool check(int x){
if(x<=n)return 0;
if(po(q,n,x)!=1)return 0;
int per=x-1;
int t=per;
while(t>1){
int o=v[t];
if(po(q,per/o,x)==1)per/=o;
if(n>per)return 0;
t/=o;
}
return 1;
}
int main(){
scanf("%d%d",&q,&n);
for(i=2;i<N;i++){
if(!v[i]){
p[tot++]=i;
v[i]=i;
}
for(j=0;j<tot&&1LL*i*p[j]<N;j++){
v[i*p[j]]=p[j];
if(i%p[j]==0)break;
}
}
for(i=0;i<tot;i++)if(check(p[i]))ans[++fin]=p[i];
printf("%d\n",fin);
for(i=1;i<=fin;i++)printf("%d ",ans[i]);
}
10. Tickets
按题意模拟。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 1e6 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n;
char a[N], b[N];
int main()
{
while(~scanf("%s%s",a,b))
{
int n = strlen(a);
int A = 0, B = 0;
for(int i = 0; i < n; ++i)
{
if(a[i] < b[i])++A;
else if(a[i] > b[i])++B;
}
printf("%d\n%d\n",A,B);
}
return 0;
} /*
【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 */
11. Logarithm smoothing
二分答案$mid$,将$f(x)=c\ln x$的图像往上下分别平移$mid$。
从$(a,f(a)+mid)$开始往右沿着切线走,判断走$n$步是否可以到达$b$之后的位置即可。
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long double ld;
const int T=50;
int n;ld C,A,B,OFFSET;
void read(ld&x){
double t;
scanf("%lf",&t);
x=t;
}
void write(ld x){
printf("%.15f",(double)x);
}
bool down(ld A,ld B,int n);
bool up(ld A,ld B,int n){
//printf("up %d\n",n);
if(A>=B)return 1;
if(n<1)return 0;
ld y=C*log(A)+OFFSET;
//f'(x)=C/x
ld L=A,R=B+10;
for(int i=0;i<T;i++){
ld mid=(L+R)/2;
if((C*log(mid)-OFFSET-y)/(mid-A)<C/mid)L=mid;else R=mid;
}
return down(L,B,n);
}
bool down(ld A,ld B,int n){
//printf("down %d\n",n);
if(A>=B)return 1;
if(n<1)return 0;
ld y=C*log(A)-OFFSET;
//f'(x)=C/x
ld k=C/A;
ld L=A,R=B+10;
for(int i=0;i<T;i++){
ld mid=(L+R)/2;
if(y+(mid-A)*k<C*log(mid)+OFFSET)L=mid;else R=mid;
}
return up(L,B,n-1);
}
bool check(ld _mid){
OFFSET=_mid;
if(down(A,B,n))return 1;
if(up(A,B,n))return 1;
return 0;
}
int main(){
int Case;
scanf("%d",&Case);
while(Case--){
scanf("%d",&n);
read(C);
read(A);
read(B);
ld l=0,r=C*(log(B)-log(A))/2;
for(int i=0;i<100;i++){
ld mid=(l+r)/2;
if(check(mid))r=mid;else l=mid;
}
write(l);
puts("");
}
}
12. Outer space signals
KMP求出两个串最左和最右出现位置然后判断即可。
时间复杂度$O(n)$。
#include<cstdio>
#include<cstring>
const int N=1000010;
int Case,na,nb,nc,i,bl,br,cl,cr;char a[N],b[N],c[N];
int nxt[N];
void solve(int n,char*a,int m,char*b,int&l,int&r){
int i,j;
for(nxt[1]=j=0,i=2;i<=n;nxt[i++]=j){
while(j&&a[j+1]!=a[i])j=nxt[j];
if(a[j+1]==a[i])j++;
}
l=r=0;
for(i=1,j=0;i<=m;i++){
while(j&&a[j+1]!=b[i])j=nxt[j];
if(a[j+1]==b[i])j++;
if(j==n){
if(!l)l=i;
r=i;
j=nxt[j];
}
}
}
bool check(){
if(!bl||!cl)return 0;
if(cr-nc+1>bl)return 1;
if(br-nb+1>cl)return 1;
return 0;
}
int main(){
scanf("%d",&Case);
while(Case--){
scanf("%s%s%s",a+1,b+1,c+1);
na=strlen(a+1);
nb=strlen(b+1);
nc=strlen(c+1);
solve(nb,b,na,a,bl,br);
solve(nc,c,na,a,cl,cr);
puts(check()?"YES":"NO");
}
}