给定数组 a a a ,求 ∑ i = 1 n ∑ j = i + 1 n a i a j \sum\limits_{i=1}\limits^n\sum\limits_{j=i+1}\limits^n a_ia_j i=1∑nj=i+1∑naiaj
∑ i = 1 n ∑ j = i + 1 n a i a j = ∑ i = 1 n a i ( ∑ j = i + 1 n a j ) = ∑ i = 1 n a i ( s u m [ n ] − s u m [ i ) \sum\limits_{i=1}\limits^n\sum\limits_{j=i+1}\limits^n a_ia_j = \sum\limits_{i=1}\limits^na_i(\sum\limits_{j=i+1}\limits^n a_j) = \sum\limits_{i=1}\limits^na_i(sum[n]-sum[i) i=1∑nj=i+1∑naiaj=i=1∑nai(j=i+1∑naj)=i=1∑nai(sum[n]−sum[i)
s u m sum sum 是 a a a 数组的前缀和,预处理前缀和即可
#include
using namespace std;
#define fi first
#define se second
const int maxn = 2e5+10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
int n;
ll a[maxn], sum[maxn];
ll ans;
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i];
sum[i] = sum[i-1] + a[i];
}
for(int i = 1; i <= n; i++){
ans += a[i]*(sum[n]-sum[i]);
}
cout << ans << endl;
return 0;
}
给定数组 a a a 和整数 x x x, m m m 次询问。每次询问 a [ l . . . r ] a[l...r] a[l...r] 中是否存在两个数异或值为 x x x
对于每个 a i a_i ai,找到左边最近的 a j a_j aj ,满足 a i ⊕ a j = x a_i \oplus a_j = x ai⊕aj=x,即 f [ i ] = j f[i] = j f[i]=j 。然后线段树维护 f f f 的最大值
对于每次询问 ( l , r ) (l,r) (l,r) ,判断 f [ i ] f[i] f[i] 是否大于等于 l l l
#include
using namespace std;
#define fi first
#define se second
const int maxn = 1e6+10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
int n, m, x;
int pos[1<<21], a[maxn], f[maxn];
int t[maxn<<2];
inline int ls(int x){return x << 1;}
inline int rs(int x){return x << 1 | 1;}
void pushup(int k){
t[k] = max(t[ls(k)], t[rs(k)]);
}
void build(int k, int l, int r){
if(l == r){
t[k] = f[l];
return;
}
int mid = (l+r) >> 1;
build(ls(k), l, mid);
build(rs(k), mid+1, r);
pushup(k);
}
int query(int k, int l, int r, int x, int y){
if(x <= l && y >= r)
return t[k];
int mid = (l+r) >> 1;
int res = 0;
if(x <= mid)
res = max(res, query(ls(k), l, mid, x, y));
if(y > mid)
res = max(res, query(rs(k), mid+1, r, x, y));
return res;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> m >> x;
for(int i = 1; i <= n; i++){
cin >> a[i];
f[i] = pos[a[i]^x];
pos[a[i]] = i;
}
build(1, 1, n);
for(int i = 1; i <= m; i++){
int l, r;
cin >> l >> r;
if(query(1, 1, n, l, r) >= l)
cout << "yes" << endl;
else
cout << "no" << endl;
}
return 0;
}
高度为 n n n 的树,初始位于高度为 0 0 0 处。当从高度 i − 1 i-1 i−1 爬到 i i i 处时,有 p i p_i pi 的概率掉回高度为 0 0 0 处。询问爬到高度为 n n n 处的时间的期望值
令 f i f_i fi 为从高度 i i i 爬到树顶的期望时间,则 f i − 1 = p i f 0 + ( 1 − p i ) f i + 1 f_{i-1} = p_if_0+(1-p_i)f_i+1 fi−1=pif0+(1−pi)fi+1 f n = 0 f_n = 0 fn=0,答案为 f 0 f_0 f0
因为 f n = 0 f_n = 0 fn=0 ,可以用 f 0 f_0 f0 和常数表示 f i f_i fi ,即 f i = a i f 0 + b i f_i = a_if_0+b_i fi=aif0+bi代入上式可得: f i − 1 = [ p i + a i ( 1 − p i ) ] f 0 + [ ( 1 − p i ) b i + 1 ] f_{i-1} = [p_i+a_i(1-p_i)]f_0+[(1-p_i)b_i+1] fi−1=[pi+ai(1−pi)]f0+[(1−pi)bi+1] 因此 a i − 1 = p i + a i ( 1 − p i ) a_{i-1} = p_i+a_i(1-p_i) ai−1=pi+ai(1−pi) b i − 1 = ( 1 − p i ) b i + 1 b_{i-1} = (1-p_i)b_i+1 bi−1=(1−pi)bi+1
且 f 0 = a 0 f 0 + b 0 f_0 = a_0f_0+b_0 f0=a0f0+b0,得 f 0 = b 0 1 − a 0 f_0 = \frac{b_0}{1-a_0} f0=1−a0b0
#include
using namespace std;
#define fi first
#define se second
const int maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
ll p[maxn], a[maxn], b[maxn];
ll qpow(ll a, ll b){
ll res = 1;
while(b){
if(b & 1)
res = res * a % mod;
b = b >> 1;
a = a * a % mod;
}
return res;
}
ll inv(int x){
return qpow(x, mod-2);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n;
cin >> n;
for(int i = 1; i <= n; i++){
int x, y;
cin >> x >> y;
p[i] = x * inv(y) % mod;
}
a[n-1] = p[n], b[n-1] = 1;
for(int i = n-1; i >= 1; i--){
a[i-1] = (p[i]+a[i]*(1-p[i])) % mod;
b[i-1] = ((1-p[i])*b[i]+1) % mod;
}
ll ans = ((b[0]*inv(1-a[0]))%mod+mod)%mod;
cout << ans << endl;
return 0;
}
河里有高度 h i h_i hi 的石头,每次从石头起跳石头的高度就会下降1。具有跳跃能力 y y y 时,能跳不超过 y y y 的距离。每次上课都需要往返,询问上完 x x x 次课的最小跳跃能力
二分答案,对于跳跃能力 k k k ,如果每个长度为 k k k 的高度和都大于等于 2 x 2x 2x ,则跳跃能力 k k k 是可行的。
必要性:如果有一个长度为 k k k 的区间高度和小于 2 x 2x 2x,则必须有青蛙不经过这个区间,对跳跃能力 k k k 来说是不可能的。
充分性: 2 x 2x 2x 只青蛙第一次跳之后,所有青蛙分布在 [ 1 , k ] [1,k] [1,k] 中,第二次跳考虑将青蛙分布在 [ 2 , k + 1 ] [2,k+1] [2,k+1] 中。
如果 h 1 ≤ h k + 1 h_1 \le h_{k+1} h1≤hk+1 :可以将第一块石头上的所有青蛙跳到第 k + 1 k+1 k+1 块
如果 h 1 > h k + 1 h_1 > h_{k+1} h1>hk+1 :将第一块石头上的部分青蛙跳到第 k + 1 k+1 k+1 块石头,因为 [ 2 , k + 1 ] [2,k+1] [2,k+1] 是可以容纳 2 x 2x 2x 只青蛙的,将第一块石头上的剩余青蛙跳到 [ 2 , y ] [2,y] [2,y] 中未满的石头。
#include
using namespace std;
#define fi first
#define se second
const int maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
int n, x, ans;
int h[maxn], sum[maxn];
bool check(int k){
for(int i = 1; i+k-1 <= n; i++)
if(sum[i+k-1] - sum[i-1] < 2*x)
return false;
return true;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> x;
for(int i = 1; i < n; i++){
cin >> h[i];
sum[i] = sum[i-1] + h[i];
}
sum[n] = INF;
int l = 1, r = n;
while(l <= r){
int mid = (l+r) >> 1;
if(check(mid)){
r = mid-1;
ans = mid;
}
else
l = mid+1;
}
cout << ans << endl;
return 0;
}
T T T 次询问,每次询问 a a a 是否能表示成 x 1 y 1 ⋅ x 2 y 2 x_1^{y_1} \cdot x_2^{y_2} x1y1⋅x2y2 的形式。 ( a ≤ 1 0 18 , y 1 , y 2 ≥ 2 ) (a \le 10^{18},\quad y_1,y_2 \ge 2) (a≤1018,y1,y2≥2)
将 a a a 质因数分解: a = ∏ i = 1 k p i q i a = \prod\limits_{i=1}\limits^{k}p_i^{q_i} a=i=1∏kpiqi 。需要 q i ≥ 2 q_i \ge 2 qi≥2
设 x 1 x_1 x1 中有 k 1 k_1 k1 个 p i p_i pi , x 2 x_2 x2 中有 k 2 k_2 k2 个 p i p_i pi ,则 k 1 y 1 + k 2 y 2 = q i k_1y_1+k_2y_2 = q_i k1y1+k2y2=qi
容易发现, y 1 = 2 , y 2 = 3 y1 = 2,y_2 = 3 y1=2,y2=3 对所有 q i q_i qi 均有非负整数解。
所以问题转化为 a = x 1 2 x 2 3 a = x_1^2x_2^3 a=x12x23
a = x 1 2 x 2 3 ≤ 1 0 18 a = x_1^2x_2^3 \le 10^{18} a=x12x23≤1018 。如果 p > 4000 p > 4000 p>4000, p 5 > 1 0 18 p^5 > 10^{18} p5>1018,所以只需要暴力分解 4000 4000 4000 之内的质因子即可。对于 p i > 4000 p_i>4000 pi>4000 , q i q_i qi 的取值只能为 2,3,4,只需要判断是否为平方数或者立方数
#include
using namespace std;
#define fi first
#define se second
const int maxn = 4e3+10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
#define int ll
bool notprime[maxn];
int prime[maxn], tot;
void init(int n){
for(int i = 2; i <= n; i++){
if(!notprime[i]){
prime[++tot] = i;
for(int j = 2*i; j <= n; j += i)
notprime[j] = true;
}
}
}
bool check(ll x){
ll y = pow(x, 0.5);
if(y*y == x || (y+1)*(y+1) == x)
return true;
y = pow(x, 1.0/3);
if(y*y*y ==x || (y+1)*(y+1)*(y+1) == x)
return true;
return false;
}
void solve(){
ll x;
cin >> x;
for(int i = 1; i <= tot; i++){
if(x % prime[i] == 0){
int cnt = 0;
while(x % prime[i] == 0){
cnt++;
x /= prime[i];
}
if(cnt == 1){
cout << "no" << endl;
return;
}
}
}
if(check(x))
cout << "yes" << endl;
else
cout << "no" << endl;
return;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
init(4000);
int T;
cin >> T;
while(T--)
solve();
return 0;
}
长度为 n n n 的数组 A A A ,给出 m m m 个区间和 ( l , r , s ) (l, r, s) (l,r,s), 即 ∑ i = l r A [ i ] = s \sum\limits_{i=l}\limits^r A[i] = s i=l∑rA[i]=s。 q q q 次询问 ( l , r ) (l, r) (l,r) 的区间和,即 ∑ i = l r A [ i ] \sum\limits_{i=l}\limits^r A[i] i=l∑rA[i]
数据范围: 1 ≤ n , m , q ≤ 1 0 5 , − 1 0 12 ≤ s ≤ 1 0 12 , 1 ≤ l ≤ r ≤ n 1 ≤ n, m, q ≤ 10^5,−10^{12} ≤ s ≤ 10^{12},1 ≤ l ≤ r ≤ n \quad 1≤n,m,q≤105,−1012≤s≤1012,1≤l≤r≤n数据保证没有矛盾
带权并查集。
对于区间和 ( l , r , s ) (l, r, s) (l,r,s) ,若 l l l 和 r r r 有共同的祖先,不需要合并。如果没有共同的祖先,进行合并操作并更新 v a l val val 值。为了保证连续性,区间为左开右闭即 ( l − 1 , r ] (l-1,r] (l−1,r] 。
查询时,如果 l − 1 l-1 l−1 和 r r r 没有共同祖先,输出 UNKNOWN,否则输出 v a l [ r ] − v a l [ l − 1 ] val[r]-val[l-1] val[r]−val[l−1]
时间复杂度 O ( ( m + q ) l o g n ) O((m+q)logn) O((m+q)logn)
#include
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
inline ll read(){//读入优化
char ch;
ll sign = 1;
while((ch=getchar())<'0'||ch>'9')
if(ch == '-')
sign = -1;
ll res = ch-48;
while((ch=getchar())>='0'&&ch<='9')
res = res*10+ch-48;
return res*sign;
}
ll fa[maxn], val[maxn];
ll n, m, q, l, r, s;
ll find(ll x){
if(x != fa[x]){
ll fx = fa[x];
fa[x] = find(fx);
val[x] += val[fx];
}
return fa[x];
}
void merge(ll x, ll y, ll z){
ll fx = find(x);
ll fy = find(y);
fa[fy] = fx;
val[fy] = val[x]+z-val[y];
}
void query(int x, int y){
ll fx = find(x);
ll fy = find(y);
if(fx != fy)
printf("UNKNOWN\n");
else
printf("%lld\n", val[y] - val[x]);
}
int main(){
cin >> n >> m >> q;
for(int i = 1; i <= n; i++)
fa[i] = i;
for(int i = 1; i <= m; i++){
l = read(), r = read(), s = read();
l--;
merge(l, r, s);
}
for(int i = 1; i <= q; i++){
l = read(), r = read();
l--;
query(l, r);
}
return 0;
}