牛客多校第一場
A. Equivalent Prefixes
題意:兩個序列相等的條件是RMQ(u,l,r) = RMQ(u,l,r),() ,RMQ(u,l,r)代表序列u,的任意區間(l,r)的最小值的序號,求一個最大的P,使得和相等
思路:
我們假設 ,也就是左邊序號最大的小於的數字的位置,
我們用單調棧去求這個last,求得以後
那麼我們求序列[1,r]的RMQ,就是找到last[r],last[last[r]],last[last[last[r]],的值
如果兩個序列的last數組相同,那麼就證明
AC代碼:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e5 + 7;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
typedef pair<int, int> pis;
int a[maxn], b[maxn];
int lasta[maxn], lastb[maxn];
stack<pis> sta;
int main() {
int n;
while(~scanf("%d", &n)) {
for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);
for (int i = 1; i <= n; i ++) scanf("%d", &b[i]);
while(!sta.empty()) sta.pop();
sta.push(pis{0, 0});
for (int i = 1; i <= n; i ++) {
while(sta.top().first > a[i]) sta.pop();
lasta[i] = sta.top().second;
sta.push((pis{a[i], i}));
}
while(!sta.empty()) sta.pop();
sta.push(pis{0, 0});
for (int i = 1; i <= n; i ++) {
while(sta.top().first > b[i]) sta.pop();
lastb[i] = sta.top().second;
sta.push((pis{b[i], i}));
}
int cnt = 0;
for (int i = 1; i <= n; i ++) {
if(lasta[i] == lastb[i]) cnt ++;
else break;
}
cout << cnt << endl;
}
return 0;
}
B.Integration
題意:
已知
求:
思路:
我們先算
我們設
那麼
AC代碼:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e5 + 7;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
typedef pair<int, int> pis;
ll a[maxn], b[maxn];
int n;
ll ex_gcd(ll a, ll b, ll &x, ll &y) {
if(!b) {
x = 1; y = 0;
return a;
}
ll d = ex_gcd(b, a % b, x, y);
ll t = x;
x = y; y = t - a / b * y;
return d;
}
ll getInv(ll a, ll p) {
ll x, y;
ex_gcd(a, p, x, y);
x = ((x % p) + p) % p;
return x;
}
ll solve(ll x, int idx) {
ll res = x;
for (int i = 1; i <= n; i ++) {
if(i == idx) continue;
res *= (b[i] - b[idx] + mod) % mod;
res %= mod;
}
return getInv(res, mod);
}
int main() {
while(~scanf("%d", &n)) {
for (int i = 1; i <= n; i ++) {
scanf("%lld", &a[i]);
b[i] = a[i] * a[i] % mod;
}
ll ans = 0;
for (int i = 1; i <= n; i ++)
ans = (ans + solve(a[i], i)) % mod;
printf("%lld\n", ans * getInv(2, mod) % mod);
}
return 0;
}
C:Euclidean Distance
題意:
給你一些點,讓你找一些,使得最小,滿足
思路:
聽說題解是用拉格朗日乘子法,但我也不會,
我看到有別人用的是貪心
因爲所有的都是除以m的,所以我們把和都乘以m,那麼我們就變成了用m步使得面積最小(負數的面積不能變小隻能變大)
那麼貪心的做法就是把大的儘量的變小,因爲是排過序的,所以前面的要比後面的大。
每次都試着把前i-1塊變得跟第i塊平齊,如果不能就把前(i-1)塊全部減小,保持前面的平齊
AC代碼:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 5e5 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
ll a[maxn];
bool cmp(ll a, ll b) {
return a > b;
}
ll gcd(ll a, ll b) {
return !b ? a : gcd(b, a % b);
}
int main() {
ll n, m;
while(~scanf("%lld %lld", &n, &m)) {
for (int i = 1; i <= n; i ++)
scanf("%lld", &a[i]);
sort(a + 1, a + n + 1, cmp);
ll k = m;
for (int i = 2; i <= n; i ++) {
if(k > (a[i-1] - a[i]) * (i-1)) {
k -= 1ll * (a[i-1] - a[i]) * (i-1);
}else {
for (int j = 1; j <= i-1; j ++)
a[j] = 1ll* (i-1) * a[i-1] - k;
for (int j = i; j <= n; j ++)
a[j] = 1ll * a[j] * (i-1);
m = 1ll * m * (i-1);
k = 0;
break;
}
}
if(k) {
for (int i = 1; i <= n; i ++)
a[i] = 1ll * (a[n] * n) - k;
m = 1ll * m * n;
}
ll ans = 0;
for (int i = 1; i <= n; i ++)
ans = (ans + 1ll * a[i] * a[i]);
m = 1ll * m * m;
ll k1 = gcd(ans, m);
ans /= k1;
m /= k1;
if(m == 1) printf("%lld\n", ans);
else printf("%lld/%lld\n", ans, m);
}
return 0;
}