生活随笔
收集整理的這篇文章主要介紹了
牛客练习赛 66
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
A.平方數
討論一下最接近它的兩個平方數即可。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std
;
typedef long long ll
;
int main()
{IO
;int T
=1;while(T
--){ll x
;cin
>>x
;ll y
=sqrt(x
);ll z
=y
+1;z
*=z
;y
*=y
;if(abs(y
-x
)<abs(z
-x
)) cout
<<y
<<'\n';else cout
<<z
<<'\n';}return 0;
}
B.異或圖
首先我們要知道一個性質x⊕x=0x\oplus x=0x⊕x=0
設起點為sss,終點為ttt,如果存在一條路徑s?>p1?>p2?>pi?>es->p_1->p_2->p_i->es?>p1??>p2??>pi??>e那么說明有以下等式a[s]⊕a[p1]=ka[p1]⊕a[p2]=ka[p2]⊕a[pi]=ka[pi]⊕a[t]=ka[s]\oplus a[p_1]=k \\ a[p_1]\oplus a[p_2]=k \\a[p_2]\oplus a[p_i]=k\\ a[p_i]\oplus a[t]=ka[s]⊕a[p1?]=ka[p1?]⊕a[p2?]=ka[p2?]⊕a[pi?]=ka[pi?]⊕a[t]=k我們不難發現如果有一條路徑能夠使得s?>??>ts->\dots->ts?>??>t說明a[s]⊕a[e]=0/ka[s] \oplus a[e]=0/ka[s]⊕a[e]=0/k,并且明顯如果a[s]⊕a[e]=ka[s] \oplus a[e]=ka[s]⊕a[e]=k答案是111,如果a[s]⊕a[e]=0a[s] \oplus a[e]=0a[s]⊕a[e]=0需要判斷是否有中間點即a[e]⊕ka[e]\oplus ka[e]⊕k是否存在即可,如存在答案是222,否則不存在路徑答案是?1-1?1
剛開始以為2202^{20}220很大數組開不下,用unordered_map存的個數,結果一直T,最后發現數組能開下直接就A了。~。·
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std
;
typedef long long ll
;
const int N
=1100010;
int a
[N
],cnt
[N
];
int n
,q
;
int main()
{scanf("%d%d",&n
,&q
);for(int i
=1;i
<=n
;i
++){scanf("%d",&a
[i
]);cnt
[a
[i
]]++;}while(q
--){int k
,st
,ed
;scanf("%d%d%d",&k
,&st
,&ed
);if((a
[st
]^a
[ed
])==k
) printf("1\n");else{int x
=a
[st
]^k
,y
=a
[ed
]^k
;if(x
!=y
||!cnt
[x
]) printf("-1\n");else printf("2\n");}}return 0;
}
C.公因子
輾轉相除法擴展可得以下式子,然后不難亂搞求解
gcd(a1,a2,a3,…,an)=gcd(a1,a2?a1,a3?a2,…,an?an?1)gcd(a_1,a_2,a_3,\dots,a_n)=gcd(a_1,a_2-a_1,a_3-a_2,\dots,a_n-a_{n-1})gcd(a1?,a2?,a3?,…,an?)=gcd(a1?,a2??a1?,a3??a2?,…,an??an?1?)
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std
;
typedef long long ll
;
const int N
=1100010;
ll a
[N
];
int n
;
ll
gcd(ll a
,ll b
)
{return b
?gcd(b
,a
%b
):a
;
}
int main()
{IO
;int T
=1;while(T
--){cin
>>n
;for(int i
=1;i
<=n
;i
++) cin
>>a
[i
];sort(a
+1,a
+1+n
);ll d
=a
[2]-a
[1];for(int i
=3;i
<=n
;i
++) d
=gcd(d
,a
[i
]-a
[i
-1]);if(d
<0) d
=-d
;ll res
=abs(a
[1]/d
*d
-a
[1]);cout
<<d
<<' '<<res
<<'\n';}return 0;
}
E.騷區間
參考大佬題解
一般這種區間左右端點都不確定的情況,我們嘗試固定一段點,求另一個端點的可行范圍。
對于i位置作為左端點,考慮如何求右端點的合法區間,由于a[i]是第二小值,在[i+1,n]范圍內第一個小于a[i]的位置是l1,在[i+1,n]范圍內第二個小于a[i]的位置是r1,不難看出對于[l1,r1)范圍滿足左區間限制條件。
對于i位置作為右端點,我們同樣可以如法炮制的求出滿足右端點限制條件的區間(l2,r2]。
我們可以維護一個樹狀數組差分求得答案。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std
;
typedef long long ll
;
const int N
=1000010;
int a
[N
],n
;
struct node
{int l
,r
;int mx
,mn
;
}tree
[N
*4];
void pushup(int u
)
{tree
[u
].mx
=max(tree
[u
<<1].mx
,tree
[u
<<1|1].mx
);tree
[u
].mn
=min(tree
[u
<<1].mn
,tree
[u
<<1|1].mn
);
}
void build(int u
,int l
,int r
)
{tree
[u
]={l
,r
,0,n
+1};if(l
==r
){tree
[u
].mx
=tree
[u
].mn
=a
[l
];return;}int mid
=l
+r
>>1;build(u
<<1,l
,mid
),build(u
<<1|1,mid
+1,r
);pushup(u
);
}
int query_min(int u
,int l
,int r
,int x
)
{if(l
>r
) return n
+1;if(tree
[u
].mn
>=x
) return n
+1;if(tree
[u
].l
==tree
[u
].r
) return tree
[u
].l
;int mid
=tree
[u
].l
+tree
[u
].r
>>1;if(l
>mid
) return query_min(u
<<1|1,l
,r
,x
);else if(r
<=mid
) return query_min(u
<<1,l
,r
,x
);else{if(tree
[u
<<1].mn
<x
){int v
=query_min(u
<<1,l
,r
,x
);return v
!=n
+1?v
:query_min(u
<<1|1,l
,r
,x
);}elsereturn query_min(u
<<1|1,l
,r
,x
);}
}
int query_max(int u
,int l
,int r
,int x
)
{if(l
>r
) return 0;if(tree
[u
].mx
<=x
) return 0;if(tree
[u
].l
==tree
[u
].r
) return tree
[u
].l
;int mid
=tree
[u
].l
+tree
[u
].r
>>1;if(l
>mid
) return query_max(u
<<1|1,l
,r
,x
);else if(r
<=mid
) return query_max(u
<<1,l
,r
,x
);else{if(tree
[u
<<1|1].mx
>x
) {int v
=query_max(u
<<1|1,l
,r
,x
);return v
?v
:query_max(u
<<1,l
,r
,x
);}else return query_max(u
<<1,l
,r
,x
);}
}
vector
<int> p
[N
];
int cnt
[N
];
int lowbit(int x
)
{return x
&-x
;
}
void update(int k
,int x
)
{for(;k
<=n
;k
+=lowbit(k
)) cnt
[k
]+=x
;
}
ll
query(int k
)
{ll now
=0;for(;k
;k
-=lowbit(k
)) now
+=cnt
[k
];return now
;
}
int main()
{int T
=1;while(T
--){scanf("%d",&n
);for(int i
=1;i
<=n
;i
++) scanf("%d",&a
[i
]);build(1,1,n
);ll res
=0;for(int i
=1;i
<=n
;i
++){int l
=query_min(1,i
+1,n
,a
[i
]);int r
=query_min(1,l
+1,n
,a
[i
]);if(l
!=n
+1) p
[l
].push_back(i
);if(r
!=n
+1) p
[r
].push_back(-i
);for(auto t
:p
[i
]){if(t
>0) update(t
,1);else update(-t
,-1);}r
=query_max(1,1,i
-1,a
[i
]);l
=query_max(1,1,r
-1,a
[i
]);res
+=query(r
)-query(l
);}printf("%lld\n",res
);}return 0;
}
要加油哦~
總結
以上是生活随笔為你收集整理的牛客练习赛 66的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。