1、斜率
可以证明如果两点之间还有一点的话那么原来的两个点连线一定不会是最大斜率
然后我就写了个沙茶分治…………
其实根据上面的推论只用枚举相邻的两个点,扫一遍就可以了
1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 using namespace std; 5 typedef pair<int,int> P; 6 int n,a,b; 7 P p[500001]; 8 double ans; 9 void solve(int l,int r) 10 { 11 if (l>=r) return; 12 int mid=(l+r)/2; 13 for (int i=l;i<=r;i++) if (i!=mid) 14 { 15 ans=max(ans,double(p[mid].second-p[i].second)/(p[mid].first-p[i].first)); 16 } 17 solve(l,mid-1);solve(mid+1,r); 18 } 19 int main() 20 { 21 freopen("slope.in","r",stdin); 22 freopen("slope.out","w",stdout); 23 scanf("%d",&n); 24 for (int i=1;i<=n;i++) 25 { 26 scanf("%d%d",&a,&b); 27 p[i]=P(a,b); 28 } 29 sort(p+1,p+n+1); 30 ans=double(p[2].second-p[1].second)/(p[2].first-p[1].first); 31 solve(1,n); 32 printf("%.3f",ans); 33 }
2、最优路径
这不就是原来做的过路费吗……
1 #include <cstdio> 2 #include <iostream> 3 #include <queue> 4 #include <cstring> 5 #define ll long long 6 using namespace std; 7 typedef pair<int,int> P; 8 struct E{ 9 int next,to,w; 10 }e[250001]; 11 priority_queue<P,vector<P>,greater<P> > que; 12 int n,m,a,b,c,sz=0,head[501],v[501],reg[501],f[501]; 13 ll w[501][501]; 14 void insert(int a,int b,int w) 15 { 16 sz++; 17 e[sz].next=head[a]; 18 head[a]=sz; 19 e[sz].to=b; 20 e[sz].w=w; 21 } 22 void dijkstra(int s) 23 { 24 memset(reg,0,sizeof(reg)); 25 memset(f,0x7f,sizeof(f)); 26 f[s]=1; 27 que.push(P(0,s)); 28 while(!que.empty()) 29 { 30 int x=que.top().second;que.pop(); 31 if (reg[x]) continue; 32 reg[x]=1; 33 for (int i=head[x];i;i=e[i].next) 34 { 35 if (v[e[i].to]<=v[s]&&f[e[i].to]>max(f[x],e[i].w)) 36 { 37 f[e[i].to]=max(f[x],e[i].w); 38 que.push(P(f[e[i].to],e[i].to)); 39 } 40 } 41 } 42 for (int i=1;i<=n;i++) 43 for (int j=1;j<=n;j++) 44 if (reg[i]&®[j]) w[i][j]=min(w[i][j],(ll)max(f[i],f[j])*v[s]); 45 } 46 int main() 47 { 48 freopen("path.in","r",stdin); 49 freopen("path.out","w",stdout); 50 ios::sync_with_stdio(false); 51 memset(w,0x7f,sizeof(w)); 52 cin>>n>>m; 53 for (int i=1;i<=n;i++) cin>>v[i]; 54 for (int i=1;i<=m;i++) 55 { 56 cin>>a>>b>>c; 57 insert(a,b,c);insert(b,a,c); 58 } 59 for (int i=1;i<=n;i++) dijkstra(i); 60 for (int i=1;i<=n;i++) 61 { 62 for (int j=1;j<=n;j++) 63 { 64 if (i==j){ 65 cout<<0<<" "; 66 }else{ 67 if (w[i][j]==w[0][0]) 68 cout<<-1<<" "; 69 else 70 cout<<w[i][j]<<" "; 71 } 72 } 73 cout<<endl; 74 } 75 }
3、小G的线段树
如果一个点上存在赋值语句,只有最后一个赋值语句会起作用,所以所有赋值语句的期望就是操作数的平均数
k个赋值操作把序列分割成了k+1个空位,注意到所有加法操作的位置都是等效的,由于加法操作只会在最后一个空位起作用,所以所有加法语句的期望就是操作数的总和乘上起作用的概率1/(k+1)
赋值语句的期望加上加法语句的期望就是所求的答案,然后在整个序列上差分即可
因为空间开成100001,当n=100000时右边界差分会访问越界,所以我决定以后都用const int N=所需空间+10的方式开空间
1 #include <cstdio> 2 typedef double db; 3 typedef long long ll; 4 using namespace std; 5 const int N=100010; 6 int n,m,q,c,l,r,x,a[N]; 7 ll s1[N],s2[N],z2[N],w1=0,w2=0,w3=0; 8 db ans[N]; 9 int main() 10 { 11 freopen("segment.in","r",stdin); 12 freopen("segment.out","w",stdout); 13 scanf("%d%d%d",&n,&m,&q); 14 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 15 for (int i=1;i<=m;i++) 16 { 17 scanf("%d%d%d%d",&c,&l,&r,&x); 18 if (c==1) 19 s1[l]+=x,s1[r+1]-=x; 20 else 21 s2[l]+=x,s2[r+1]-=x,z2[l]++,z2[r+1]--; 22 } 23 for (int i=1;i<=n;i++) 24 { 25 w1+=s1[i],w2+=s2[i],w3+=z2[i]; 26 if (w3==0) 27 ans[i]=ans[i-1]+a[i]+w1; 28 else 29 ans[i]=ans[i-1]+1.0*w2/w3+1.0*w1/(w3+1); 30 } 31 for (int i=1;i<=q;i++) 32 { 33 scanf("%d%d",&l,&r); 34 printf("%.3lf\n",ans[r]-ans[l-1]); 35 } 36 }