2019牛客暑期多校训练营(第一场)

传送门

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

•代码

 1 #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 }
View Code

 

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之间的欧几里得距离即为∑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个单位

如图

 

 关于分子分母处理看代码中的注释

 

•代码

 1 、#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 }
View Code

 

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

参考此处

•代码

 1 #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 }
View Code

 

F.Random Point in Triangle

•题意

给定三个顶点的坐标形成一个三角形(也可能不能构成)

存在一点P使得Sp=max{SPAB,SPBC,SPCA}

求36*(Sp的数学期望)

•思路

正解证明到现在也不会,等到会了再来补上,结论是22倍的面积

以下是非正解

纯暴力模拟找规律来着,

当SPAB=SPBC=SPCA时,P为三角形的重心

 就假设一个很大的三角形,先求出面积,
然后求出重心,再让去移动整数点,相当于模拟P点在上移。
一直上移到顶点处,算一下是多少倍的面积
因为给的坐标是整数,输出答案也是整数,就很容易往面积的偶数倍上去想
(因为奇数倍可能不是整数
多测几组数据,然后多wa几发就出来了...
所以就有了上面的非正解...(大雾

 •代码

暴力模拟的代码

#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;
}
View Code

AC代码

#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;
    }
}
View Code

 

转载于:https://www.cnblogs.com/MMMinoz/p/11209898.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值