【前言】
第二场,感觉这场水了,实际上比较好做的1002和1003都没做。
1010这种数学题还是不太会,数学只靠一个人还是太难了。
然后就是罚时依然多。
rk82,校3/9
1001. I love cube
【题意】
一个边长为 n − 1 n-1 n−1的正常放置的立方体(dddd),在它的棱上取三个整点,有多少种取法使得构成一个等边三角形且三边均平行于三个普通平面之一(就 x O y xOy xOy和另外俩)。
n ≤ 5 × 1 0 7 n\leq 5\times 10^7 n≤5×107
【思路】
首先
1
×
1
1\times1
1×1的方案显然有8个,
2
×
2
2\times2
2×2可以分解为
8
8
8个
1
×
1
1\times1
1×1和一个
2
×
2
2\times 2
2×2,就是
72
72
72,后面的也很容易类似递推出来,大概是:
f
[
i
]
=
8
⋅
∑
k
=
1
k
−
1
(
i
−
k
+
1
)
3
f[i]=8\cdot\sum_{k=1}^{k-1}(i-k+1)^3
f[i]=8⋅k=1∑k−1(i−k+1)3
发现就是一个立方求和。
复杂度 O ( 1 ) O(1) O(1)
【参考代码】
#include<bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i=(a),i##ss=(b);i<=i##ss;i++)
#define dwn(i,a,b) for(int i=(a),i##ss=(b);i>=i##ss;i--)
#define deb(x) cerr<<(#x)<<":"<<(x)<<'\n'
#define pb push_back
#define fi first
#define se second
#define hvie '\n'
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
int yh(){
int ret=0;bool f=0;char c=getchar();
while(!isdigit(c)){if(c==EOF)return -1;if(c=='-')f=1;c=getchar();}
while(isdigit(c))ret=(ret<<3)+(ret<<1)+(c^48),c=getchar();
return f?-ret:ret;
}
const int maxn=5e7+5;
signed main(){
int n;
ll mod=1e9+7;
dwn(_,yh(),1){
n=yh()-1;
n%=mod;
cout<<(2ll*n%mod*n%mod*(n+1)%mod*(n+1)%mod)%mod<<hvie;
}
return 0;
}
1002. I love tree
【题意】
给定一棵 n n n个节点的树,有 q q q次操作为两种类型:
-
给 ( u , v ) (u,v) (u,v)的路径加 1 ∼ k 1\sim k 1∼k的平方,即从 u u u开始 + 1 , + 4 , + 9 , + 16 … +1,+4,+9,+16\dots +1,+4,+9,+16…
-
求某个点的点权
n , q ≤ 1 0 5 n,q\leq 10^5 n,q≤105
【思路】
树上路径问题考虑树剖,实际上问题可以转化为给区间加一个二次函数。
不妨设对 [ h , t ] [h,t] [h,t]增加了 ( x − h ) 2 (x-h)^2 (x−h)2,展开后是 x 2 + h 2 − 2 x h x^2+h^2-2xh x2+h2−2xh,只需要对三个标记分开维护即可。
复杂度 O ( n log 2 n ) O(n\log^2 n) O(nlog2n)
【参考代码】
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a),i##ss=(b);i<=i##ss;i++)
#define dwn(i,a,b) for(int i=(a),i##ss=(b);i>=i##ss;i--)
#define deb(x) cerr<<(#x)<<":"<<(x)<<'\n'
#define pb push_back
#define fi first
#define se second
#define hvie '\n'
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
int yh(){
int ret=0;bool f=0;char c=getchar();
while(!isdigit(c)){if(c==EOF)return -1;if(c=='-')f=1;c=getchar();}
while(isdigit(c))ret=(ret<<3)+(ret<<1)+(c^48),c=getchar();
return f?-ret:ret;
}
const int maxn=1e5+5;
int n,q;
int s2(int n){
return (ll)n*(n+1)*(2ll*n+1)/6;
}
struct node{
ll a,b,c;
ll val(int p){
return a*p*p+b*p+c;
}
};
struct sgt{
node nd[maxn<<2];
ll ta[maxn<<2],tb[maxn<<2],tc[maxn<<2];
#define ls (v<<1)
#define rs (v<<1|1)
#define mid ((l+r)>>1)
void add(int v,ll a,ll b,ll c){
nd[v].a+=a;nd[v].b+=b;nd[v].c+=c;
ta[v]+=a; tb[v]+=b; tc[v]+=c;
}
void push_down(int v){
add(ls,ta[v],tb[v],tc[v]);
add(rs,ta[v],tb[v],tc[v]);
ta[v]=tb[v]=tc[v]=0;
}
void modify(int v,int l,int r,int al,int ar,ll a,ll b,ll c){
if(al>ar)return;
if(al<=l&&ar>=r) return add(v,a,b,c);
push_down(v);
if(al<=mid) modify(ls,l,mid,al,ar,a,b,c);
if(ar>mid) modify(rs,mid+1,r,al,ar,a,b,c);
}
ll query(int v,int l,int r,int p){
if(l==r){
return nd[v].val(p);
}
push_down(v);
return p<=mid?query(ls,l,mid,p):query(rs,mid+1,r,p);
}
void process(int l,int r,ll d){// add((x+d)^2)
modify(1,1,n,l,r,1,2*d,d*d);
}
}s;
vector<int>adj[maxn];
int fa[maxn],dep[maxn],son[maxn],siz[maxn];
int top[maxn],L[maxn],R[maxn],dfn[maxn],tott;
void dfs1(int x,int f=0){
fa[x]=f;
dep[x]=dep[f]+1;
siz[x]=1;
for(int y:adj[x])if(y!=f){
dfs1(y,x);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]]) son[x]=y;
}
}
void dfs2(int x,int to){
top[x]=to;
L[x]=++tott;dfn[tott]=x;
if(son[x]) dfs2(son[x],to);
for(int y:adj[x])if(y!=fa[x]&&y!=son[x]){
dfs2(y,y);
}
R[x]=tott;
}
int lca(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) y=fa[top[y]];
else x=fa[top[x]];
}
return dep[x]>dep[y]?y:x;
}
void up(int x,int z,int ori){
int X=x;
while(top[x]!=top[z]){
int t=top[x];
//ori+ dep[X]-dep[x]+L[x]
//(i+d)^2
s.process(L[t],L[x],-L[x]-ori-dep[X]+dep[x]);
x=fa[t];
}
//cout<<-L[x]-ori-dep[X]+dep[x]<<endl;
s.process(L[z],L[x],-L[x]-ori-dep[X]+dep[x]);
}
void down(int x,int z,int ori){
while(top[x]!=top[z]){
int t=top[x];
//x : ori+dep[x]-dep[z] + i-L[x]
s.process(L[t],L[x],ori+dep[x]-dep[z]-L[x]);
x=fa[t];
}
// cout<<-L[x]+ori-dep[z]+dep[x]<<endl;
s.process(L[z]+1,L[x],ori+dep[x]-dep[z]-L[x]);
}
int main(){
freopen("my.in","r",stdin);
n=yh();
rep(i,1,n-1) {int x=yh(),y=yh();adj[x].pb(y);adj[y].pb(x);}
dfs1(1);
dfs2(1,1);
dwn(_,yh(),1){
int op=yh(),x=yh();
if(op==1){
int y=yh(),z=lca(x,y);
up(x,z,1);down(y,z,1+dep[x]-dep[z]);
}
else{
cout<<s.query(1,1,n,L[x])<<hvie;
}
}
return 0;
}
1003. I love playing games
【题意】
一幅 n n n个点无向图,Alice和Bob分别在两个点,两个人轮流走。要求:除终点外,两个人不能走到同一个点。
先到终点的人赢,如果Alice到终点后轮到Bob走,Bob也到终点了,那么平局。
n ≤ 1000 n\leq 1000 n≤1000
【思路】
首先,离终点严格近的人一定赢,因为远的那个人一定追不上。那么由此我们也可以看出,两个人一定是沿着最短路图来走。
令 f [ x ] [ y ] [ 0 / 1 ] f[x][y][0/1] f[x][y][0/1]表示当前Alice在 x x x,Bob在 y y y当前轮到谁走,值代表必胜/平局/必败。
枚举最短路图上的边暴力转移即可。
复杂度 O ( n 2 ) O(n^2) O(n2)
【参考代码】
//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#include <immintrin.h>
//#include <emmintrin.h>
#include <bits/stdc++.h>
using namespace std;
#define rep(i,h,t) for (int i=h;i<=t;i++)
#define dep(i,t,h) for (int i=t;i>=h;i--)
#define ll long long
#define me(x) memset(x,0,sizeof(x))
#define IL inline
#define rint register int
inline ll rd(){
ll x=0;char c=getchar();bool f=0;
while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x;
}
char ss[1<<24],*A=ss,*B=ss;
IL char gc()
{
return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
}
template<class T>void maxa(T &x,T y)
{
if (y>x) x=y;
}
template<class T>void mina(T &x,T y)
{
if (y<x) x=y;
}
template<class T>void read(T &x)
{
int f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
while(c=gc(),c>47&&c<58) x=x*10+(c^48); x*=f;
}
const int mo=1e9+7;
ll fsp(int x,int y)
{
if (y==1) return x;
ll ans=fsp(x,y/2);
ans=ans*ans%mo;
if (y%2==1) ans=ans*x%mo;
return ans;
}
struct cp {
ll x,y;
cp operator +(cp B)
{
return (cp){x+B.x,y+B.y};
}
cp operator -(cp B)
{
return (cp){x-B.x,y-B.y};
}
ll operator *(cp B)
{
return x*B.y-y*B.x;
}
int half() { return y < 0 || (y == 0 && x < 0); }
};
struct re{
int a,b,c;
};
vector<re> ve;
const int N=2005;
int dis[N],n,m,q;
int h[N][N][2];
int ans2=0;
vector<int> bb[N];
vector<int> v1[N];
int g(int x,int y,int z,int k)
{
ans2++;
if (k==0&&(x==z||y==z))
{
if (x==z&&y==z) return 2;
if (x==z) return 1;
return 3;
}
if (h[x][y][k]) return h[x][y][k];
int tt;
if (k==0)
{
tt=3;
for (auto i:v1[x])
if ((i!=y||i==z))
{
int kk=g(i,y,z,k^1);
tt=min(tt,4-kk);
}
h[x][y][k]=tt;
} else
{
tt=3;
for (auto i:v1[y])
if ((i!=x||i==z))
{
int kk=g(x,i,z,k^1);
tt=min(tt,4-kk);
}
h[x][y][k]=tt;
}
ve.push_back((re){x,y,k});
return h[x][y][k];
}
int main()
{
ios::sync_with_stdio(false);
int T;
cin>>T;
ll anst=0,ansa=0;
while(T--)
{
rep(i,1,n) bb[i].clear();
cin>>n>>m; anst+=m; ansa+=n;
rep(i,1,n) dis[i]=1e9;
int x,y,z;
cin>>x>>y>>z;
rep(i,1,m)
{
int x,y;
cin>>x>>y;
bb[x].push_back(y); bb[y].push_back(x);
}
dis[z]=0;
queue<int> q;
q.push(z);
while (!q.empty())
{
int x=q.front(); q.pop();
for (auto v:bb[x])
{
if (dis[v]==1e9) {dis[v]=dis[x]+1; q.push(v);}
}
}
int ans=0;
// cerr<<x<<" "<<y<<" "<<z<<" "<<dis[x]<<" "<<dis[y]<<endl;
if (dis[x]>dis[y]) { cout<<3<<endl; continue;}
if (dis[x]<dis[y]) { cout<<1<<endl; continue;}
if (dis[x]==1e9)
{
cout<<2<<endl;
continue;
}
if (dis[x]==dis[y])
{
rep(i,1,n)
for (auto j:bb[i])
if (dis[i]==dis[j]+1) v1[i].push_back(j);
cout<<g(x,y,z,0)<<endl;
for (auto v:ve)
{
h[v.a][v.b][v.c]=0;
}
ans+=ve.size();
// cerr<<ve.size()<<endl;
ve.clear();
}
rep(i,1,n) v1[i].clear();
}
// cerr<<ansa<<" "<<anst<<endl;
// cerr<<ans2<<endl;
//cerr<<ans<<endl;
return 0;
}
1004. I love counting
【题意】
给定一个长度为 n n n的序列 a i a_i ai,有 q q q个询问,每次询问一段区间 [ l , r ] [l,r] [l,r]有多少不同的数异或上 x x x以后 ≤ y \leq y ≤y
n , q ≤ 1 0 5 , a i < 2 30 n,q\leq 10^5,a_i<2^{30} n,q≤105,ai<230
【思路】
这个题和上一场的那个1010一样都是询问不同的数,那么我们直接尝试莫队。
我们只需要记录经过Trie上每个节点的数字的个数和它最右的位置就行了。
不过每次修改和查询都是 O ( log a ) O(\log a) O(loga)的,所以最后复杂度是 O ( n n log a + n log a ) O(n\sqrt n \log a+n\log a) O(nnloga+nloga),可以卡过去。
std写了一个Trie上每个节点记录子树内所有点,对于一个询问,包含了Trie上最多 log a \log a loga个子树,询问挂在子树上,对每颗子树做一次二维数点即可(区间颜色数,转化为询问前驱<询问左端点且查询点在区间内)。这个复杂度是 O ( n log n log 2 a ) O(n\log n\log ^2a) O(nlognlog2a)
【参考代码】
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
const int MAXM = 18;
int B;
int t, n, m;
int bl[N];
int ans[N], A[N];
struct query {
int id, l, r, a, b;
bool operator < (const query &x) const {
return (bl[l] ^ bl[x.l]) ? bl[l] < bl[x.l] : ((bl[l] & 1) ? r < x.r : r > x.r);
}
} q[N];
struct Node {
int sz, num;
int ch[2];
} T[N * MAXM * 30];
int rt, cntT;
int Floor[30];
void insert(int u, int x, int p, int add) {
for (int i = p; i >= 0; --i) {
int o = (x >> i) & 1;
if (!T[u].ch[o]) T[u].ch[o] = ++cntT;
Floor[i] = u;
u = T[u].ch[o];
}
T[u].num += add;
if (add == 1 && T[u].num == 1) {
T[u].sz = 1;
for (int i = 0; i <= p; ++i) T[Floor[i]].sz++;
} else if (add == -1 && T[u].num == 0) {
T[u].sz = 0;
for (int i = 0; i <= p; ++i) T[Floor[i]].sz--;
}
}
void add(int x) {
insert(rt, A[x], 16, 1);
}
void del(int x) {
insert(rt, A[x], 16, -1);
}
int query(int x, int y) {
int u = rt, ans = 0;
for (int i = 16; i >= 0; --i) {
if (!T[u].sz) return ans;
int ox = (x >> i) & 1;
int oy = (y >> i) & 1;
if (oy == 0) {
if (T[u].ch[ox]) u = T[u].ch[ox];
else return ans;
} else {
if (T[u].ch[ox]) ans += T[T[u].ch[ox]].sz;
if (T[u].ch[ox ^ 1]) u = T[u].ch[ox ^ 1];
else return ans;
}
}
return ans + T[u].sz;
}
int read() {
int ret = 0, f = 1; char c = getchar();
while (!isdigit(c)) {
if (c == '-')f = 0;
c = getchar();
}
while (isdigit(c)) ret = ret * 10 + (c ^ 48), c = getchar();
return f ? ret : -ret;
}
int main() {
n = read();
for (int i = 1; i <= n; ++i) {
A[i] = read();
}
m = read();
B = n / sqrt(m) + 1;
for (int i = 1; i <= n; ++i) bl[i] = i / B;
for (int i = 1; i <= m; ++i) {
q[i].l = read();
q[i].r = read();
q[i].a = read();
q[i].b = read();
q[i].id = i;
}
sort(q + 1, q + m + 1);
int l = 1, r = 0;
for (int i = 1; i <= m; ++i) {
int a = q[i].a, b = q[i].b;
while (l < q[i].l) del(l++);
while (l > q[i].l) add(--l);
while (r < q[i].r) add(++r);
while (r > q[i].r) del(r--);
ans[q[i].id] = query(a, b);
}
for (int i = 1; i <= m; ++i) {
printf("%d\n", ans[i]);
}
return 0;
}
1005. I love string
【题意】
给定一个长度为 n n n的字符串,从左往右每次遇到一个字符可以把它放到新字符串的头或尾,问有多少种放的方式使得最后形成的新字符串字典序最小。
n ≤ 1 0 5 n\leq 10^5 n≤105
【思路】
事实上,除了最开头的连续的一段相同字符可以选择放头或放尾,其他放的方式是固定的。
所以答案是 2 x − 1 2^{x-1} 2x−1, x x x是最开头连续段长度。
复杂度 O ( n + log n ) O(n+\log n) O(n+logn)
【参考代码】
#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
using namespace std;
typedef double db;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;
const int N=5e5+10,mod=1000000007,inf=0x3f3f3f3f;
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
char s[N];
int n,cnt;
int qpow(int x,int y)
{
int ret=1;
for(;y;y>>=1,x=1ll*x*x%mod)
if(y&1) ret=1ll*ret*x%mod;
return ret;
}
int main()
{
for(int T=read();T--;)
{
n=read();scanf("%s",s+1);
cnt=0;
for(int i=2;i<=n;++i)
if(s[i]==s[i-1]) ++cnt;
else break;
printf("%d\n",qpow(2,cnt));
}
}
1006. I love sequences
【题目】
【思路】
不会。
【参考代码】
#include<bits/stdc++.h>
#define N 200009
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll a[N][2];
int n,m;
inline ll rd(){
ll x=0;char c=getchar();bool f=0;
while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x;
}
inline void MOD(ll &x){x=x>=mod?x-mod:x;}
struct matrix{
ll a[2][2];
matrix(){memset(a,0,sizeof(a));a[0][0]=a[1][1]=1;}
inline matrix operator *(const matrix &b)const{
matrix c;c.a[0][0]=c.a[1][1]=0;
for(int i=0;i<2;++i)
for(int j=0;j<2;++j)
for(int k=0;k<2;++k)
MOD(c.a[i][j]+=a[i][k]*b.a[k][j]%mod);
return c;
}
};
matrix rev,wk;
inline void wok(int cnt,int l,int r,int L,int R,matrix tag);
inline void upd(int cnt,int l,int r,int tag,int L,int R,int x);
inline void clear(matrix &a){
memset(a.a,0,sizeof(a.a));
a.a[0][0]=a.a[1][1]=1;
}
struct seg{
ll sum[2],sm,adtag[2],sum1[2];
matrix tag;
}tr[N<<2];
inline void pushup(int cnt){
MOD(tr[cnt].sm=tr[cnt<<1].sm+tr[cnt<<1|1].sm);
MOD(tr[cnt].sum[0]=tr[cnt<<1].sum[0]+tr[cnt<<1|1].sum[0]);
MOD(tr[cnt].sum[1]=tr[cnt<<1].sum[1]+tr[cnt<<1|1].sum[1]);
MOD(tr[cnt].sum1[0]=tr[cnt<<1].sum1[0]+tr[cnt<<1|1].sum1[0]);
MOD(tr[cnt].sum1[1]=tr[cnt<<1].sum1[1]+tr[cnt<<1|1].sum1[1]);
}
inline void pushdown(int cnt,int l,int r){
int mid=(l+r)>>1;
wok(cnt<<1,l,mid,l,mid,tr[cnt].tag);
wok(cnt<<1|1,mid+1,r,mid+1,r,tr[cnt].tag);
clear(tr[cnt].tag);
for(int i=0;i<2;++i){
upd(cnt<<1,l,mid,i,l,mid,tr[cnt].adtag[i]);
upd(cnt<<1|1,mid+1,r,i,mid+1,r,tr[cnt].adtag[i]);
tr[cnt].adtag[i]=0;
}
}
void build(int cnt,int l,int r){
if(l==r){
tr[cnt].sum[0]=a[l][0];
tr[cnt].sum[1]=a[l][1];
tr[cnt].sm=a[l][0]*a[l][1]%mod;
tr[cnt].sum1[0]=a[l][0]*a[l][0]%mod;
tr[cnt].sum1[1]=a[l][1]*a[l][1]%mod;
return;
}
int mid=(l+r)>>1;
build(cnt<<1,l,mid);
build(cnt<<1|1,mid+1,r);
pushup(cnt);
}
void upd(int cnt,int l,int r,int tag,int L,int R,int x){
if(l>=L&&r<=R){
MOD(tr[cnt].adtag[tag]+=x);
(tr[cnt].sum1[tag]+=1ll*x*x%mod*(r-l+1)%mod+2ll*x*tr[cnt].sum[tag]%mod)%=mod;
MOD(tr[cnt].sum[tag]+=1ll*x*(r-l+1)%mod);
MOD(tr[cnt].sm+=1ll*x*tr[cnt].sum[tag^1]%mod);
return;
}
int mid=(l+r)>>1;
pushdown(cnt,l,r);
if(L<=mid)upd(cnt<<1,l,mid,tag,L,R,x);
if(mid<R)upd(cnt<<1|1,mid+1,r,tag,L,R,x);
pushup(cnt);
}
void wok(int cnt,int l,int r,int L,int R,matrix x){
if(l>=L&&r<=R){
ll sm=tr[cnt].sm;
ll c=x.a[0][0],d=x.a[0][1],e=x.a[1][0],f=x.a[1][1];
ll xx=tr[cnt].sum1[0],yy=tr[cnt].sum1[1];
tr[cnt].sm=tr[cnt].sum1[0]*c%mod*d+tr[cnt].sum1[1]*e%mod*f+tr[cnt].sm*(c*f%mod+d*e%mod);
tr[cnt].sm=tr[cnt].sm%mod;
tr[cnt].sum1[0]=(c*c%mod*xx+e*e%mod*yy+2ll*c*e%mod*sm)%mod;
tr[cnt].sum1[1]=(d*d%mod*xx+f*f%mod*yy+2ll*d*f%mod*sm)%mod;
xx=tr[cnt].sum[0];yy=tr[cnt].sum[1];
tr[cnt].sum[0]=(xx*c+yy*e)%mod;
tr[cnt].sum[1]=(xx*d+yy*f)%mod;
xx=tr[cnt].adtag[0];yy=tr[cnt].adtag[1];
tr[cnt].adtag[0]=(xx*x.a[0][0]+yy*x.a[1][0])%mod;
tr[cnt].adtag[1]=(xx*x.a[0][1]+yy*x.a[1][1])%mod;
tr[cnt].tag=tr[cnt].tag*x;
return;
}
int mid=(l+r)>>1;
pushdown(cnt,l,r);
if(mid>=L)wok(cnt<<1,l,mid,L,R,x);
if(mid<R)wok(cnt<<1|1,mid+1,r,L,R,x);
pushup(cnt);
}
ll q(int cnt,int l,int r,int L,int R){
if(l>=L&&r<=R)return tr[cnt].sm;
int mid=(l+r)>>1;
pushdown(cnt,l,r);
ll ans=0;
if(mid>=L)ans+=q(cnt<<1,l,mid,L,R);
if(mid<R)MOD(ans+=q(cnt<<1|1,mid+1,r,L,R));
return ans;
}
int main(){
n=rd();
for(int i=1;i<=n;++i){
a[i][0]=rd();a[i][1]=rd();
}
build(1,1,n);
m=rd();
int l,r,tag,x,opt;
while(m--){
opt=rd();
wk.a[0][0]=wk.a[0][1]=3;
wk.a[1][0]=2;
wk.a[1][1]=mod-2;
rev.a[0][0]=rev.a[1][1]=0;
rev.a[0][1]=rev.a[1][0]=1;
if(opt==1){
tag=rd();l=rd();r=rd();x=rd();
upd(1,1,n,tag,l,r,x);
}
if(opt==2){
l=rd();r=rd();
wok(1,1,n,l,r,wk);
}
if(opt==3){
l=rd();r=rd();
wok(1,1,n,l,r,rev);
}
if(opt==4){
l=rd();r=rd();
printf("%lld\n",q(1,1,n,l,r));
}
}
return 0;
}
1007. I love data structure
【题意】
给定一个长度为 n n n的序列,每个位置是 ( a i , b i ) (a_i,b_i) (ai,bi),有 q q q个操作
- 将 [ l , r ] [l,r] [l,r]区间的所有 a i + x a_i+x ai+x或 b i + x b_i+x bi+x
- 将 [ l , r ] [l,r] [l,r]区间的所有数变换为 ( 3 a i + 2 b i , 3 a i − 2 b i ) (3a_i+2b_i,3a_i-2b_i) (3ai+2bi,3ai−2bi)
- 将 [ l , r ] [l,r] [l,r]区间每个 a i , b i a_i,b_i ai,bi交换
- 求 ∑ i = l r a i ⋅ b i \sum_{i=l}^ra_i\cdot b_i ∑i=lrai⋅bi
【思路】
这个维护的东西是一个向量,简单分析后可以发现,实际上我们只需要维护 ( a , b , a 2 , b 2 , a b , 1 ) (a,b,a^2,b^2,ab,1) (a,b,a2,b2,ab,1)这个向量,那么上面所有的操作实际上都是对向量的线性变换,可以用矩阵来表示。那么我们就可以用线段树来维护向量和以及矩阵标记求出答案。
复杂度 O ( 6 3 ⋅ n log n ) ) O(6^3\cdot n\log n)) O(63⋅nlogn))
【参考代码】
#include<bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i=(a),i##ss=(b);i<=i##ss;i++)
#define dwn(i,a,b) for(int i=(a),i##ss=(b);i>=i##ss;i--)
#define deb(x) cerr<<(#x)<<":"<<(x)<<'\n'
#define pb push_back
#define fi first
#define se second
#define hvie '\n'
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
int yh(){
int ret=0;bool f=0;char c=getchar();
while(!isdigit(c)){if(c==EOF)return -1;if(c=='-')f=1;c=getchar();}
while(isdigit(c))ret=(ret<<3)+(ret<<1)+(c^48),c=getchar();
return f?-ret:ret;
}
const int maxn=4e5+5,mod=1000000007;
int mul(int a,int b){return (ll)a*b%mod;}
int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
struct mat{
int m[6][6];
mat(){}
mat(int x){
rep(i,0,5)rep(j,0,5)m[i][j]=x*(i==j);
}
bool not_id(){
rep(i,0,5)rep(j,0,5)if(m[i][j]!=(i==j))return 1;
return 0;
}
void print(){
rep(i,0,5){
rep(j,0,5){
cout<<m[i][j]<<" ";
}cout<<endl;
}
}
};
mat operator*(const mat&A,const mat&B){
mat c;
rep(i,0,5)rep(j,0,5) c.m[i][j]=0;
rep(k,0,5)rep(i,0,5)if(A.m[i][k])rep(j,0,5){
int &x=c.m[i][j];
x=add(x,mul(A.m[i][k],B.m[k][j]));
}
return c;
}
struct node{
int x[6];
mat tag;
};
node nd[maxn<<2];
#define ls (v<<1)
#define rs (v<<1|1)
#define mid ((l+r)>>1)
void mul(mat &b,int *a){
int v[6]={};
rep(i,0,5){
int &t=v[i]=0;
rep(k,0,5){
t=add(t,mul(b.m[i][k],a[k]));
}
}
rep(i,0,5) a[i]=v[i];
}
void push_up(int v){
rep(i,0,5) nd[v].x[i]=add(nd[ls].x[i],nd[rs].x[i]);
}
void MUL(int v,mat &b){
mul(b,nd[v].x);
nd[v].tag= (b*nd[v].tag) ;
}
void push_down(int v){
if(nd[v].tag.not_id()){
MUL(ls,nd[v].tag);
MUL(rs,nd[v].tag);
nd[v].tag=mat(1);
}
}
void build(int v,int l,int r){
nd[v].tag=mat(1);
if(l==r){
int a=yh(),b=yh();
nd[v].x[0]=a;
nd[v].x[1]=b;
nd[v].x[2]=mul(a,a);
nd[v].x[3]=mul(b,b);
nd[v].x[4]=mul(a,b);
nd[v].x[5]=1;
return;
}
build(ls,l,mid);build(rs,mid+1,r);
push_up(v);
}
void modify(int v,int l,int r,int al,int ar,mat&b){
if(al<=l&&ar>=r) return MUL(v,b);
push_down(v);
if(al<=mid) modify(ls,l,mid,al,ar,b);
if(ar>mid) modify(rs,mid+1,r,al,ar,b);
push_up(v);
}
int ask(int v,int l,int r,int al,int ar){
if(al<=l&&ar>=r) return nd[v].x[4];
push_down(v);
int ans=0;
if(al<=mid) ans=add(ans,ask(ls,l,mid,al,ar));
if(ar>mid) ans=add(ans,ask(rs,mid+1,r,al,ar));
return ans;
}
int ask(int v,int l,int r,int al,int ar,int bb){
if(al<=l&&ar>=r) return nd[v].x[bb];
push_down(v);
int ans=0;
if(al<=mid) ans=add(ans,ask(ls,l,mid,al,ar,bb));
if(ar>mid) ans=add(ans,ask(rs,mid+1,r,al,ar,bb));
return ans;
}
int n;
mat t;
void Plus(){
int tg=yh(),l=yh(),r=yh(),x=yh();
t=mat(1);
if(tg==0){
t.m[0][5]=x;
t.m[2][0]=mul(2ll,x); t.m[2][5]=mul(x,x);
t.m[4][1]=x;
}
else{
t.m[1][5]=x;
t.m[3][1]=mul(2ll,x); t.m[3][5]=mul(x,x);
t.m[4][0]=x;
}
// t.print();
modify(1,1,n,l,r,t);
// cout<<endl;
}
void expand(){
int l=yh(),r=yh();
t=mat(0);
t.m[5][5]=1;
t.m[0][0]=3;t.m[0][1]=2;
t.m[1][0]=3;t.m[1][1]=mod-2;
t.m[2][2]=9;t.m[2][3]=4;t.m[2][4]=12;
t.m[3][2]=9;t.m[3][3]=4;t.m[3][4]=mod-12;
t.m[4][2]=9;t.m[4][3]=mod-4;
// t.print();
modify(1,1,n,l,r,t);
// rep(i,1,n){
// rep(bb,0,5)cout<<ask(1,1,n,i,i,bb)<<' ';
// puts("");
// }
// rep(i,1,n){
// cout<<ask(1,1,n,i,i)<<' ';
// }
}
void flip(){
int l=yh(),r=yh();
t=mat(1);
t.m[0][0]=0;t.m[0][1]=1;
t.m[1][0]=1;t.m[1][1]=0;
t.m[2][2]=0;t.m[2][3]=1;
t.m[3][2]=1;t.m[3][3]=0;
modify(1,1,n,l,r,t);
}
void qry(){
int l=yh(),r=yh();
cout<<ask(1,1,n,l,r)<<hvie;
}
signed main(){
n=yh();
build(1,1,n);
dwn(_,yh(),1){
int op=yh();
switch(op){
case 1:Plus();break;
case 2:expand();break;
case 3:flip();break;
case 4:qry();break;
}
}
return 0;
}
1008. I love exam
【题意】
剩下 t t t天复习有 n n n门课程, m m m门课,每门课需要花费一定的时间,可以将对应的一门课程成绩提高,问在挂至多 p p p门课的情况下,最多能将总分提高到多少。
n ≤ 50 , m ≤ 15000 , t ≤ 500 , p ≤ 3 n\leq 50,m\leq 15000,t\leq 500,p\leq 3 n≤50,m≤15000,t≤500,p≤3
【思路】
数据范围很小,所以很可做。
首先因为上课时间是任意的,我们可以预处理出 f [ i ] [ j ] f[i][j] f[i][j]表示第 i i i门课到达 j j j分花费的最少时间。
接下来就是一个背包了,只是在背包里面再记一维已经挂科的数量就行。
复杂度 O ( m t + p n t ) O(mt+pnt) O(mt+pnt)
【参考代码】
/*
* @date:2021-07-22 12:40:21
* @source:
*/
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
#define fir first
#define sec second
#define ALL(x) (x).begin(), (x).end()
#define SZ(x) (int)x.size()
#define For(i, x) for (int i = 0; i < (x); ++i)
#define Trav(i, x) for (auto & i : x)
#define pb push_back
template<class T, class G> bool chkMax(T &x, G y) {
return y > x ? x = y, 1 : 0;
}
template<class T, class G> bool chkMin(T &x, G y) {
return y < x ? x = y, 1 : 0;
}
int N, M, P, T;
vector<string> Course;
map<string, int> Map;
vector<vector<pii>> Material;
vi F;
vector<vector<pii>> f;
vi G[55][5];
void init() {
F.clear();
f.clear();
Material.clear();
Course.clear();
for (int i = 1; i <= 50; ++i) {
for (int j = 0; j < 5; ++j) {
G[i][j].clear();
}
}
Map.clear();
}
void input() {
cin >> N;
Course.resize(N + 1);
Material.resize(N + 1);
for (int i = 1; i <= N; ++i) {
cin >> Course[i];
Material[i].clear();
Map[Course[i]] = i;
}
cin >> M;
string course;
int x, y;
for (int i = 0; i < M; ++i) {
cin >> course >> x >> y;
Material[Map[course]].pb({x, y});
}
cin >> T >> P;
}
void solve() {
f.resize(N + 1);
for (int i = 1; i <= N; ++i) {
F.clear();
F.resize(101, 1e9);
F[0] = 0;
Trav(x, Material[i]) {
for (int j = 100; j >= 0; --j) {
chkMin(F[min(100, j + x.fir)], F[j] + x.sec);
}
}
for (int j = 0; j <= 100; ++j) {
if (F[j] <= T) f[i].pb({j, F[j]}); // {score, time}
}
}
for (int i = 0; i <= N; ++i) {
for (int j = 0; j <= P; ++j) {
G[i][j].resize(T + 1, -1e9);
}
}
G[0][0][0] = 0;
for (int k = 1; k <= N; ++k) {
Trav(x, f[k]) {
for (int i = T; i >= x.sec; i--) {
for (int j = P; j >= 0; --j) {
if (x.fir >= 60) chkMax(G[k][j][i], G[k - 1][j][i - x.sec] + x.fir);
else if (j) chkMax(G[k][j][i], G[k - 1][j - 1][i - x.sec] + x.fir);
}
}
}
}
int ans = -1;
for (int i = 0; i <= P; ++i) {
for (int j = 0; j <= T; ++j) chkMax(ans, G[N][i][j]);
}
cout << ans << "\n";
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t;
cin >> t;
while (t--) {
init();
input();
solve();
}
return 0;
}
1009. I love triples
【题意】
给定一个序列 a i a_i ai,问有多少个三元组 ( i , j , k ) (i,j,k) (i,j,k)满足 i < j < k i<j<k i<j<k且 a i ⋅ j ⋅ a k a_i\cdot_j\cdot a_k ai⋅j⋅ak是一个完全平方数。
n , a i ≤ 1 0 5 n,a_i\leq 10^5 n,ai≤105
【思路】
【参考代码】
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ull unsigned long long
const int N=100000+10;
const int M=100000;
const LL P=998244353;
void add(int &x,int y){
x+=y;if(x>=P)x-=P;
}
int n,m;
int a[N];
bool is_pri[N+10];
int pri[N],cntp=0;
int c[N];
int g[1050][1050];
void init_pri(){
for(int i=2;i<=M;++i){
if(!is_pri[i]) {
pri[++cntp]=i;
c[i]=i;
}
for(int j=1;j<=cntp&&pri[j]*i<=M;++j){
is_pri[pri[j]*i]=1;
c[pri[j]*i]=pri[j];
if(i%pri[j]==0) {
break;
}
}
}
}
void init(){
init_pri();m=sqrt(M);
for(int j=0;j<=m;++j) g[0][j]=j;
for(int i=1;i<=m;++i){
for(int j=0;j<i;++j) g[i][j]=g[j][i];
g[i][i]=i;
for(int j=i+1;j<=m;++j){
g[i][j]=g[i][j-i];
}
}
// cout<<pri[600]<<endl;
// for(int i=2;i*i<=M;++i){
// for(int j=i*i;j<=M;j+=i*i){
// vis[j]=1;
// }
// }
// for(int i=sqrt(M)+1;i<=M;++i){
// if(!is_pri[i]){
// for(int j=i;j<=M;j+=i){
// vis[j]=1;
// }
// }
// }
// int x=0;
// for(int i=1;i<=M;++i){
// if(!vis[i]){
// ++x;
// //cout<<x<<endl;
// }
// }
// cout<<cntp<<endl;
// cout<<x<<endl;
return;
}
LL ans;
void dfs(int x,int v1,int v2,int v3){
if(x==0){
if(v1<=v2&&v2<=v3){
if(v1==v2&&v1==v3){
ans+=(LL)a[v1]*(a[v1]-1)*(a[v1]-2)/(LL)6;
}
else if(v2==v3){
ans+=(LL)a[v2]*(a[v2]-1)/(LL)2*(LL)a[v1];
}
else{
ans+=(LL)a[v1]*a[v2]*a[v3];
}
}
return;
}
dfs(x-1,v1,v2,v3);
if(v3*pri[x]<=M&&v1*pri[x]<=M){
dfs(x-1,v1*pri[x],v2,v3*pri[x]);
}
if(v3*pri[x]<=M&&v2*pri[x]<=M){
dfs(x-1,v1,v2*pri[x],v3*pri[x]);
}
if(v1*pri[x]<=M&&v2*pri[x]<=M){
dfs(x-1,v1*pri[x],v2*pri[x],v3);
}
return;
}
void MAIN(){
int u,v,w,x,y;
scanf("%d",&n);ans=0;
memset(a,0,sizeof(a));
for(int i=1;i<=n;++i){
scanf("%d",&u);
v=1;w=1;
while(u>1){
w=c[u];x=0;
while(u%w==0){
u=u/w;
++x;
}
if(x&1) v=v*w;
}
++a[v];
}
//cout<<pri[cntp]<<endl;
int t=1;LL now;
while(pri[t+1]<=m) ++t;
dfs(t,1,1,1);
for(int i=t+1;i<=cntp;++i){
u=pri[i];
for(int j=u,v=1;j<=M;j+=u,++v){
if(!a[j]) continue;
for(int k=j,w=v;k<=M;k+=u,++w){
if(!a[k]) continue;
if(j==k){
now=(LL)a[j]*(a[j]-1)/(LL)2;
}
else{
now=(LL)a[j]*a[k];
}
x=g[v][w];
y=v*w/x/x;
if(y>=1&&y<=M){
ans+=(LL)a[y]*now;
}
}
}
}
printf("%lld\n",ans);
return;
}
int main(){
init();
int ttt=1;scanf("%d",&ttt);
while(ttt--) MAIN();
return 0;
}
1010. I love permutation
【题意】
给定一个常数 a a a和一个素数 P P P,生成序列 b x = a x % P b_x=ax\%P bx=ax%P,求 b b b中逆序对个数的奇偶性
1 0 5 10^5 105组数据, 1 < a < P ≤ 1 0 18 1<a<P\leq 10^{18} 1<a<P≤1018
【思路】
首先我们看题目要求逆序对个数的奇偶性,而事实上由于 p p p是素数,那么生成的会是一个排列。考虑一个排列的奇偶性,我们知道排列中每次交换两个数字,它的奇偶性会改变。那么问题实际上等价于它经过奇数次还是偶数次能变回 [ 1 , 2 , 3 , . . . , n ] [1,2,3,...,n] [1,2,3,...,n]这样的排列,我们称它为原排列。
怎么求交换次数?我们考虑一个排列其实对应了一个置换,对于当前排列 a i a_i ai,我们从 i i i向 a i a_i ai连边,这样可以构成若干个置换环,对于每个环,设环长为 x x x,那么这个环只需要交换 x − 1 x-1 x−1次就可以变回原排列。那么 ∑ ( x − 1 ) \sum(x-1) ∑(x−1)的奇偶性就是答案。
现在的问题就转化为了求这个环长和,而事实上,这个置换的环并不一定要是按上面的方法构造的,只需要对于每个环,进行干次置换后能变为原排列即可。
我们考虑构造 i → a ⋅ i i\rightarrow a\cdot i i→a⋅i的这样一个置换,可以发现它们是一一对应的,于是问题转化为,求最小的 k k k,使得 x a k ≡ x ( mod P ) xa^k\equiv x(\text{mod } P) xak≡x(mod P),也就是 a k ≡ 1 ( mod P ) a^k\equiv 1(\text{mod } P) ak≡1(mod P),由于 P P P是素数,由阶的那堆东西的定理可以知道, k = P − 1 k=P-1 k=P−1是一个解,而其余可能的解是是 P − 1 P-1 P−1的约数。
对于这个问题,我们只需要令 k = m ⋅ 2 p k=m\cdot 2^p k=m⋅2p,其中 m m m是一个奇数,从 m m m开始往上推,这样快速幂和推的过程都是 O ( l o g P ) O(log P) O(logP)的,就可以通过这题了。
但题解给出的方法似乎更直接:
#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
#define int long long
using namespace std;
typedef double db;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;
inline int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
/*
inline long long mul(long long x, long long y,ll P) {
long long tmp = (x * y - (long long)((long double)x / P * y + 1.0e-8) * P);
return (tmp + P) % P;
}*/
inline int mul(int x,int y,int mod)
{
__int128 t=x;t=t*y%mod;
return t;
}
inline int qpow(int x,int y,int mod)
{
int ret=1;
for(;y;y>>=1,x=mul(x,x,mod))
if(y&1) ret=mul(ret,x,mod);
return ret;
}
signed main()
{
//freopen("1.in","r",stdin);
//freopen("mine.out","w",stdout);
for(int T=read();T--;)
{
int a=read(),P=read(),t=P-1,now;
while(!(t&1)) t>>=1;
now=qpow(a,t,P);
while(now!=1) t<<=1,now=mul(now,now,P);
t=mul(t-1,(P-1ll)/t,P);
puts(t&1ll?"1":"0");
}
}
1011. I love max and multiply
【题意】
给定两个长度为 n n n的序列 A , B A,B A,B,下标从 0 ∼ n − 1 0\sim n-1 0∼n−1
定义 C k = max { A i B j } C_k=\max\{A_iB_j\} Ck=max{AiBj},其中 i & j ≥ k i\&j\geq k i&j≥k
求 ∑ i = 0 n − 1 C i \sum_{i=0}^{n-1}C_i ∑i=0n−1Ci
n ≤ 2 18 , ∣ A i ∣ , ∣ B i ∣ ≤ 1 0 9 n\leq 2^{18},|A_i|,|B_i|\leq 10^9 n≤218,∣Ai∣,∣Bi∣≤109
【思路】
这个 i & j ≥ k i\&j\geq k i&j≥k实际上我们可以改为求 D k = max ( A i B j ) D_k=\max(A_iB_j) Dk=max(AiBj),满足 i & j & k = k i\& j \&k=k i&j&k=k的,然后再从后往前取一个后缀 max \max max就行
于是我们 B B B可以分别求出 k & i = k k\&i=k k&i=k的 A , B A,B A,B的最大值和最小值,分别相乘取最大就可以得到 D k D_k Dk了。
【参考代码】
#include<bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i=(a),i##ss=(b);i<=i##ss;i++)
#define dwn(i,a,b) for(int i=(a),i##ss=(b);i>=i##ss;i--)
#define deb(x) cerr<<(#x)<<":"<<(x)<<'\n'
#define pb push_back
#define fi first
#define se second
#define hvie '\n'
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
int yh(){
int ret=0;bool f=0;char c=getchar();
while(!isdigit(c)){if(c==EOF)return -1;if(c=='-')f=1;c=getchar();}
while(isdigit(c))ret=(ret<<3)+(ret<<1)+(c^48),c=getchar();
return f?-ret:ret;
}
const int maxn=5e6+5,mod=998244353,inf=0x3f3f3f3f3f3f3f3fll;
int A[maxn],B[maxn];
int C[maxn],D[maxn];
int a[maxn],b[maxn];
ll c[maxn];
int n;
void cmax(int &x,int y){x=x>y?x:y;}
void cmin(int &x,int y){x=x<y?x:y;}
void DP(int *A,int *a,int tot){
rep(i,0,tot) A[i]=-inf;
A[tot]=(tot<n)?a[tot]:-inf;
dwn(s,tot,1){
for(int j=0;j<19;j++)if(s&(1<<j)){
int t=s^(1<<j);
cmax(A[t],max(A[s],(t<n?a[t]:-inf)));
}
}
}
void DPmin(int *A,int *a,int tot){
rep(i,0,tot) A[i]=inf;
A[tot]=(tot<n)?a[tot]:inf;
dwn(s,tot,1){
for(int j=0;j<19;j++)if(s&(1<<j)){
int t=s^(1<<j);
cmin(A[t],min(A[s],(t<n?a[t]:inf)));
}
}
}
signed main(){
dwn(_,yh(),1){
n=yh();
rep(i,0,n-1){
a[i]=yh();
}
rep(i,0,n-1){
b[i]=yh();
}
int t=30;
while(!((n>>t)&1)) t--;
t++;
int tot=(1<<t)-1;
DP(A,a,tot);
DP(B,b,tot);
DPmin(C,a,tot);
DPmin(D,b,tot);
rep(i,0,tot+1) c[i]=-inf;
dwn(i,n-1,0)
c[i]=max(max(1ll*A[i]*D[i],1ll*B[i]*C[i]),max(1ll*A[i]*B[i],1ll*C[i]*D[i]));
dwn(i,n-1,0) c[i]=max(c[i],c[i+1]);
ll ans=0;
rep(i,0,n-1){
ans=(ans+c[i]%mod)%mod;
//printf("%lld ",c[i]);
}
//puts("");
cout<<(ans+mod)%mod<<hvie;
}
return 0;
}
/*
1
4
-9 -1 -4 -1
-5 -4 -1 -1
*/
1012. I love 114514
【题意】
问一个字符串中是否有“114514”这个字串
【思路】
好臭啊
【参考代码】
#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
using namespace std;
typedef double db;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<int,ll> pil;
const int N=5e5+10,mod=1e9+7,inf=0x3f3f3f3f;
int read()
{
int ret=0,f=1;char c=getchar();
while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return f?ret:-ret;
}
char s[N];
int n;
int main()
{
for(int T=read();T--;)
{
scanf("%s",s+1);n=strlen(s+1);
int fg=0;
for(int i=1;i<=n-5;++i)
{
if(s[i]=='1' && s[i+1]=='1' && s[i+2]=='4' && s[i+3]=='5' && s[i+4]=='1' && s[i+5]=='4')
{
fg=1;
break;
}
}
if(fg) puts("AAAAAA");
else puts("Abuchulaile");
}
}