文章目录
- A.Equivalent Prefixes
- B. Integration
- C. Euclidean Distance
- E. ABBA
- F. Random Point in Triangle
- J. Fraction Comparision
链接: https://ac.nowcoder.com/acm/contest/881#question
A.Equivalent Prefixes
题目
若RMQ(u,l,r)==RMQ(v,l,r)对于所有 1 ≤ l ≤ r ≤ n 1\leq l \leq r \leq n 1≤l≤r≤n都成立,那么它们equivalent。
RMQ(w,l,r)表示[l,r]区间中最小值的下标。
已知n,m,两个数列a和b。要求一个最大的p( p ≤ n p\leq n p≤n),使得 { a 1 , a 2 , … , a p } \left\{a_{1}, a_{2}, \dots, a_{p}\right\} {a1,a2,…,ap}和 { b 1 , b 2 , … , b p } \left\{b_{1}, b_{2}, \ldots, b_{p}\right\} {b1,b2,…,bp},要求这两段equivalent。
题解
以a数列为例,对于每一个i,要求以 a i a_i ai为最小元素所能扩充到的左右区间[l,r],再对 b i b_i bi求相同的区间[l’,r’],如果r==r’,那么i+1,当前结果变为r,否则的话,当前结果就变为min(r,r’)。因为可能对于i来说,最右的区间为r,而对于i+1来说,最右的区间
求以一个值为最小值的区间可以用单调栈来完成。单调栈维护一个递增的序列。
代码
#include
using namespace std;
const int maxn = 200005;
template <class T>
void read(T &x) {
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=x*10+s-'0'; s=getchar();}
x *= f;
}
int n,a[maxn],b[maxn],l[maxn],r[maxn],p[maxn],q[maxn];
void exec() {
stack<int> s;
int temp;
for(int i=1;i<=n;i++) {
while(!s.empty() && a[s.top()]>a[i]) {
r[s.top()] = i-1;
l[i] = l[s.top()];
s.pop();
}
s.push(i);
}
if(!s.empty()) temp = s.top();
while(!s.empty()) {
r[s.top()] = temp;
s.pop();
}
for(int i=1;i<=n;i++) {
while(!s.empty() && b[s.top()]>b[i]) {
q[s.top()] = i-1;
p[i] = p[s.top()];
s.pop();
}
s.push(i);
}
if(!s.empty()) temp = s.top();
while(!s.empty()) {
q[s.top()] = temp;
s.pop();
}
}
int main() {
while(~scanf("%d",&n)) {
int res = 0x7fffffff;
for(int i=1;i<=n;i++) read(a[i]),l[i]=r[i]=i;
for(int i=1;i<=n;i++) read(b[i]),p[i]=q[i]=i;
exec();
int temp = res;
for(int i=1;i<=n;i++) {
if(r[i]!=q[i]) {
temp = min(temp,min(r[i],q[i]));
} else res = r[i];
}
res = min(res,temp);
cout << res << endl;
}
return 0;
}
B. Integration
题目
已知 ∫ 0 ∞ 1 1 + x 2 d x = π 2 \int_{0}^{\infty} \frac{1}{1+x^{2}} d x=\frac{\pi}{2} ∫0∞1+x21dx=2π,先在给定n个数。
要求 1 π ∫ 0 ∞ 1 ∏ i = 1 n ( a i 2 + x 2 ) d x \frac{1}{\pi} \int_{0}^{\infty} \frac{1}{\prod_{i=1}^{n}\left(a_{i}^{2}+x^{2}\right)} \mathrm{d} x π1∫0∞∏i=1n(ai2+x2)1dx。
因为结果是分数形式 p q \frac{p}{q} qp,要求输出一个整数解,即 ( p ⋅ q − 1 )   m o d   ( 1 0 9 + 7 ) \left(p \cdot q^{-1}\right) \bmod \left(10^{9}+7\right) (p⋅q−1)mod(109+7)。
题解
不难想到,由于要求的式子是乘法形式,应当裂项成若干个式子相加。
令 c i = 1 ∏ j ≠ i ( a j 2 − a i 2 ) c_{i}=\frac{1}{\prod_{j \neq i}\left(a_{j}^{2}-a_{i}^{2}\right)} ci=∏j̸=i(aj2−ai2)1,
则 1 ∏ ( a i 2 + x 2 ) = ∑ c i a i 2 + x 2 \frac{1}{\prod\left(a_{i}^{2}+x^{2}\right)}=\sum \frac{c_{i}}{a_{i}^{2}+x^{2}} ∏(ai2+x2)1=∑ai2+x2ci,
而 ∫ 0 ∞ c i a i 2 + x 2 d x = c i 2 a i π \int_{0}^{\infty} \frac{c_{i}}{a_{i}^{2}+x^{2}} d x=\frac{c_{i}}{2 a_{i}} \pi ∫0∞ai2+x2cidx=2aiciπ,
最终将积分化成求和的形式即可。
求 c i c_i ci的一步颇为有趣,https://www.cnblogs.com/yanlifneg/p/11211455.html#commentform
该博客中提到的方法有利用留数法裂项,个人认为是一个不错的方法。
代码
#include
using namespace std;
const int maxn = 1005;
typedef long long ll;
const ll mo = 1e9+7;
template <class T>
void read(T &x) {
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=x*10+s-'0'; s=getchar();}
x *= f;
}
ll pow(ll a,ll b,ll p) {
ll res = 1;
while(b) {
if(b&1) res = res*a%p;
a = a*a%p;
b >>= 1;
}
return res;
}
ll n;
ll a[maxn],c[maxn];
int main() {
while(~scanf("%lld",&n)) {
for(int i=0;i<n;i++) read(a[i]);
for(int i=0;i<n;i++) {
c[i] = 1;
for(int j=0;j<n;j++) {
if(j!=i) c[i] = c[i]*((a[j]*a[j]%mo-a[i]*a[i]%mo+mo)%mo)%mo;
}
}
ll res = 0;
for(int i=0;i<n;i++)
res = (res+(pow(2*c[i],mo-2,mo)%mo)*pow(a[i],mo-2,mo)%mo)%mo;
cout << res << endl;
}
return 0;
}
C. Euclidean Distance
题目
已知n个数构成的数列 { a } \{a\} {a},求n个数构成的数列 { p } \{p\} {p},使得 ∑ i = 1 n ( a i m − p i ) 2 \sum\limits_{i=1}^{n}\left(\frac{a_i}{m}-p_{i}\right)^{2} i=1∑n(mai−pi)2最小。
其中
- p 1 , p 2 , … , p n ≥ 0 p_{1}, p_{2}, \dots, p_{n} \geq 0 p1,p2,…,pn≥0
- p 1 + p 2 + ⋯ + p n = 1 p_{1}+p_{2}+\cdots+p_{n}=1 p1+p2+⋯+pn=1
题解
首先,分子分母同时乘m,为了方便计算。
要使 ( a i − p i ) 2 (a_i-p_i)^2 (ai−pi)2最小,就是让 a i a_i ai缩小一点,如果一个 a j ≤ a i a_j \leq a_i aj≤ai,那么它的缩小量 Δ \Delta Δ也一定比 a i a_i ai小,这时候,相同大小的p,我们就让个 a i a_i ai去缩小。
如果要让 a i 和 a j a_i和a_j ai和aj两个值缩小后达到最优,那么一定是将这两个都缩小成同一个值(显然),如果不缩小成同一个值的话,就违背了上一条原则。
同样的,对于n个数,先将a数列从大到小排序,再将前k个缩小成同一值(要求k尽量大),这时候p已经分完了,剩下的就不缩小了, p i p_i pi都等于0。
代码
#include
using namespace std;
const int maxn = 10005;
typedef long long ll;
template <class T>
void read(T &x) {
T f=1;x=0;char s=getchar();
while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=x*10+s-'0'; s=getchar();}
x *= f;
}
ll n,m,a[maxn],sum[maxn],k,p,q;
ll gcd(ll a,ll b) {
if(!b) return a;
return gcd(b,a%b);
}
int main() {
while(~scanf("%lld%lld",&n,&m)) {
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++) read(a[i]);
sort(a+1,a+n+1,greater<int>());
for(int i=1;i<=n;i++) sum[i] = sum[i-1] + a[i];
k = n;
for(int i=1;i<=n;i++) {
if(sum[i]-a[i+1]*i>m) {
k = i;
break;
}
}
p = (sum[k]-m)*(sum[k]-m)*k;
q = k*k;
for(int i=k+1;i<=n;i++) {
p += a[i]*a[i]*q;
}
q *= m*m;
ll gd = gcd(p,q);
p/=gd, q/=gd;
if(q==1 || !p) cout<<p<<endl;
else cout<<p<<'/'<<q<<endl;
}
return 0;
}
E. ABBA
题目
如果一个长度为2(n+m)的字符串S可以被分为n+m个子序列,其中n个为AB,m个为BA,已知n和m,问最多可以构造出多少个这样的字符串S,最终结果mod 1e9+7。
其中 0 ≤ n , m ≤ 1 0 3 0 \leq n, m \leq 10^{3} 0≤n,m≤103。
题解
对于一个字符串S,我们考虑能否把它按照题目要求分。
从头向后遍历,如果遇到一个A,那么它必然是AB的A,只有当AB分完了以后才考虑它是BA的A;同理,如果遇到一个B,那么它也一定是BA的B,只有当BA分完了以后才考虑它是AB的B。
于是我们采用DP进行构造,dp[i][j]表示用了i个A,j个B,那么就有状态转移方程:
dp[i+1][j] = dp[i+1][j] + dp[i][j],条件是i
代码
#include
using namespace std;
const int maxn = 2005;
const int mo = 1e9+7;
typedef long long ll;
template <class T>
void read(T &x) {
T f=1;x=0;char s=getchar();
while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=x*10+s-'0'; s=getchar();}
x *= f;
}
int n,m;
int main() {
while(~scanf("%d%d",&n,&m)) {
ll dp[n+m+5][n+m+5];
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
for(int i=0;i<=n+m;i++) {
for(int j=0;j<=n+m;j++) {
if(i<n || (i-n)<min(j,m))
dp[i+1][j] = (dp[i+1][j]+dp[i][j])%mo;
if(j<m || (j-m)<min(i,n))
dp[i][j+1] = (dp[i][j+1]+dp[i][j])%mo;
}
}
cout << dp[n+m][n+m] << endl;
}
return 0;
}
F. Random Point in Triangle
题目
已知三角形三个点A、B、C的坐标,现在在三角形内随机选一个点P, E = max { S P A B , S P B C , S P C A } E=\max \left\{S_{P A B}, S_{P B C}, S_{P C A}\right\} E=max{SPAB,SPBC,SPCA},求出E的期望。将结果*36,保证其是整数。
题解
随机数撒个点就求出来了。
代码
#include
using namespace std;
const int maxn = 200005;
typedef long long ll;
template <class T>
void read(T &x) {
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=x*10+s-'0'; s=getchar();}
x *= f;
}
ll a1,a2,b1,b2,c1,c2;
int main() {
while(cin>>a1>>a2>>b1>>b2>>c1>>c2) {
ll px = b1-a1;
ll py = b2-a2;
ll qx = c1-a1;
ll qy = c2-a2;
ll s = abs(px*qy-py*qx);
cout << s*11 << endl;
}
return 0;
}
J. Fraction Comparision
题目
比较 x a \frac{x}{a} ax 和 y b \frac{y}{b} by的大小。
其中 : 0 ≤ x , y ≤ 1 0 18 0 \leq x, y \leq 10^{18} 0≤x,y≤1018, 1 ≤ a , b ≤ 1 0 9 1 \leq a, b \leq 10^{9} 1≤a,b≤109
题解
直接比会溢出。可以选择用Python。
如果用C++的话,把 x a \frac{x}{a} ax写成 ⌊ x a ⌋ + x   m o d   a a \left\lfloor\frac{x}{a}\right\rfloor+\frac{x \bmod a}{a} ⌊ax⌋+axmoda,然后先比较取整的部分,如果相等的话,取模的部分再交叉相乘即可。
代码
while 1:
try:
x,a,y,b=input().split()
x = int(x)
y = int(y)
a = int(a)
b = int(b)
if x*b==y*a:
print("=")
elif x*b<y*a:
print("<")
else:
print(">")
except:
break
#include
using namespace std;
const int maxn = 200005;
typedef long long ll;
template <class T>
void read(T &x) {
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();}
while(s>='0'&&s<='9') {x=x*10+s-'0'; s=getchar();}
x *= f;
}
ll a,b,x,y;
int main() {
while(cin>>x>>a>>y>>b) {
ll p = x/a;
ll q = y/b;
if(p<q) puts("<");
else if(p>q) puts(">");
else {
x = x%a*b;
y = y%b*a;
if(x>y) puts(">");
else if(x<y) puts("<");
else puts("=");
}
}
return 0;
}