A.Equivalent Prefixes
•题意
有两个数组a,b,现给一个定义,等价:
在区间[L,R]上的任意一个区间内,ai,bi最小值的位置相等,则称这两个数组是等价的
给你两个数组a,b,求a,b存在[1,R]是等价的最大的R
•思路
利用单调栈,求出每个ai,bi是最小值的左区间
当左区间不相同时,即可得到答案
•栗子
a数组 3 1 5 2 4
左区间 1 1 3 3 5
b数组 5 2 4 3 1
左区间 1 1 3 3 1
即可得到 R=4
•代码
View Code
B.Integration
•题意
解对(109+7)取模的值
•思路
裂项相消,利用
参考这位大佬
把1/2乘进去得
然后利用费马小定理
(p/q)%mod≡p*q-1%mod
•代码
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const ll mod=1e9+7; 5 const int maxn=1e3+5; 6 ll a[maxn],b[maxn]; 7 int n; 8 9 ll quickMod(ll x,ll y) 10 { 11 ll res=1; 12 x=x%mod; 13 while(y) 14 { 15 if(y&1) 16 res=(res*x)%mod; 17 x=(x*x)%mod; 18 y>>=1; 19 } 20 return res; 21 } 22 23 int main() 24 { 25 while(scanf("%d",&n)!=EOF) 26 { 27 for(int i=1;i<=n;i++) 28 { 29 cin>>a[i]; 30 b[i]=(a[i]*a[i])%mod; 31 } 32 ll ans=0; 33 for(int i=1;i<=n;i++) 34 { 35 ll mul=a[i]*2; 36 for(int j=1;j<=n;j++) 37 { 38 if(j!=i) 39 mul=(mul*(b[j]-b[i]+mod)%mod)%mod; 40 } 41 mul=quickMod(mul,mod-2); 42 ans=(ans+mul)%mod; 43 } 44 cout<<ans<<endl; 45 } 46 return 0; 47 }
C.Euclidean Distance
•题意
给定一个N维坐标系的点A(a1/m,a2/m,a3/m,...,an/m),
寻找一个点P(p1,p2,p3,...,pn)满足p点的各坐标之和为1,且p1,p2,p3,...,pn > 0
使得A点到P点的欧几里得距离最小,
其中A与P之间的欧几里得距离即为∑n i=1(ai/m−pi),
求这个最小的欧几里得距离,若为分数则用分数形式表示。
•思路
官方题解用拉格朗日乘子法做的,但是我不会(o(╥﹏╥)o
翻到这位大佬的博客,数形结合太形象了_(:з」∠)_
对于每个数 我们先不看分母,后来直接除分母就阔以
我们要使得减去pi后的ai平方和最小,那么是ai中较大的数减小的收益一定比使较小的数变小的收益大
对于所有的a[i],按从大到小排序,
来看下排序后的图
接下来我们需要确定P的坐标,也就是将 -m(因为在欧几里得距离中A和P的坐标是直接相减关系)分配到这个图
如何分配m呢?依次把最高堆的推向比较低的堆,直到不够再向下一堆(pos+1)的水平线推进为止,我们将m中未分配完称为rest
这时候未分配的rest再平均分配到所推进的前pos堆里去,也就是把这pos堆再往下推进rest/pos个单位
如图
关于分子分母处理看代码中的注释
•代码
View Code1 、#include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int maxn=1e4+5; 5 int a[maxn]; 6 int main() 7 { 8 int n,m; 9 while(~scanf("%d%d",&n,&m)) 10 { 11 for(int i=1;i<=n;i++) 12 cin>>a[i]; 13 sort(a+1,a+1+n,greater<int>()); 14 ll rest=m; //p[i]的总分配价值是 1 ,因为 ∑pi=m,也就是 m/m 15 int pos=1; //pos 标记能够分配p[i] 到第 pos 个 16 while(pos<n) 17 { 18 if(rest<(a[pos]-a[pos+1])*pos)//如果不能继续向下一水平线推 19 break; 20 rest-=(a[pos]-a[pos+1])*pos; 21 pos++; 22 } 23 24 //直到不能再往下一个堆(pos+1)的水平线推, 25 //那么剩余的可以再让前pos堆水平下推rest/pos个单位 26 //最终前pos堆的值 都是a[pos]-rest/pos, 27 //然后分子分母同乘pos,分子变为(a[pos]*pos-rest) 28 //平方后分子为(a[pos]*pos-rest)²,分母为(m*pos)² 29 //因为一共有pos堆分配到的,所以∑的结果分子为pos倍的 30 ll ansa=(a[pos]*pos-rest)*(a[pos]*pos-rest)*pos; 31 for(int i=pos+1;i<=n;i++) //分配不到的 a[i],直接加上 32 ansa+=a[i]*a[i]*pos*pos; //因为分子乘了pos倍,记得平方 33 34 ll ansb=m*m*pos*pos; //分母(m*pos)² 35 ll gcd=__gcd(ansa,ansb); //求gcd 约分 36 if(gcd%ansb==0) 37 cout<<(ansa/ansb)<<endl; 38 else 39 cout<<ansa/gcd<<"/"<<ansb/gcd<<endl; 40 } 41 }
E.ABBA
•题意
有一个2(n+m)的序列,其中包括n各AB子序列,m个BA子序列
问这个序列有多少种情况,对109+7取模
•思路
定义dp[i][j]为有i个A,j个B的方案数
所以转移方程为
dp[i+1][j]=dp[i+1][j]+dp[i][j]
dp[i][j+1]=dp[i][j+1]+dp[i][j]
那怎么才能保证有n个AB呢?
前面的A的个数i比B的个数j多n的话,至少会形成n个AB
同理前面的B的个数j比A的个数多m的话,至少会形成m个BA
参考此处
•代码
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const ll mod=1e9+7; 5 const int maxn=1e3+5; 6 ll dp[maxn*2][maxn*2]; 7 int n,m; 8 int main() 9 { 10 while(~scanf("%d%d",&n,&m)) 11 { 12 for(int i=0;i<=n+m;i++) 13 for(int j=0;j<=n+m;j++) 14 dp[i][j]=0; 15 dp[0][0]=1; 16 17 for(int i=0;i<=n+m;i++) 18 { 19 for(int j=0;j<=n+m;j++) 20 { 21 if(i-j<n)//此时小于n个AB 22 dp[i+1][j]=(dp[i+1][j]+dp[i][j])%mod; 23 if(j-i<m)//此时小于m个BA 24 dp[i][j+1]=(dp[i][j+1]+dp[i][j])%mod; 25 } 26 } 27 cout<<dp[n+m][n+m]<<endl; 28 } 29 }
F.Random Point in Triangle
•题意
给定三个顶点的坐标形成一个三角形(也可能不能构成)
存在一点P使得Sp=max{SPAB,SPBC,SPCA}
求36*(Sp的数学期望)
•思路
正解证明到现在也不会,等到会了再来补上,结论是22倍的面积
以下是非正解
纯暴力模拟找规律来着,
当SPAB=SPBC=SPCA时,P为三角形的重心
就假设一个很大的三角形,先求出面积,然后求出重心,再让去移动整数点,相当于模拟P点在上移。一直上移到顶点处,算一下是多少倍的面积因为给的坐标是整数,输出答案也是整数,就很容易往面积的偶数倍上去想(因为奇数倍可能不是整数多测几组数据,然后多wa几发就出来了...所以就有了上面的非正解...(大雾
•代码
暴力模拟的代码
View Code#include<bits/stdc++.h> using namespace std; double gets(int x1,int x2,int x3,int yl,int y2,int y3) { return abs(((x2-x1)*(y3-yl)-(x3-x1)*(y2-yl))); } int main() { int x1,x2,x3,yl,y2,y3; cin>>x1>>yl>>x2>>y2>>x3>>y3; int s=gets(x1,x2,x3,yl,y2,y3); cout<<"总面积:"<<s<<" 1/3面积:"<<1.0*s/3<<endl; double py=1.0*s/6/(x2-x3); cout<<"重心Py:"<<py<<endl; int tots=0; int num=0; for(int i=0;py<=y3;i++) { py+=1; num++; int ss=gets(x1,x2,(x1+x2)/2,yl,y2,py); tots+=ss; cout<<"上移"<<i<<"个:S="<<ss<<" 面积和:"<<tots<<endl; } double p=1.0*tots/(1.0*num)/(1.0*s); cout<<p<<endl; cout<<"倍数:"<<p*36<<endl; }AC代码
View Code#include<bits/stdc++.h> using namespace std; #define ll long long ll x1,yl,x2,y2,x3,y3; ll s; int main() { while(cin>>x1) { cin>>yl>>x2>>y2>>x3>>y3; s=((x2-x1)*(y3-yl)-(x3-x1)*(y2-yl)); cout<<abs(11*s)<<endl; } }