暑假集训日记——7.30(牛客)

【一】n的约数
题解:
在这里插入图片描述
2)然后很容易发现一个规律:如果两个数的约数个数相同,那么指数大小按递减顺序排列的话所获得的数更小。
举个例子:
6个约数: 12 = 2 2 ∗ 3 , 18 = 2 ∗ 3 2 12=2^2 *3, 18=2 * 3^2 12=223,18=232
24个约数: 360 = 2 3 ∗ 3 2 ∗ 5 , 540 = 2 2 ∗ 3 3 ∗ 5 360=2^3 *3^2 *5, 540=2^2 * 3^3 *5 360=23325,540=22335
因为我们关注的就是寻找最大数目的约数,所以不需要考虑这个满足条件的数字具体是什么,所以直接考虑如何构造约数,使得原数字尽量小,然后判断这个数字是否处于题目给定范围内的,如果处于那么这个约数的数目是存在的,如果不处于,那么就不存在。

#include<bits/stdc++.h>
#define mp make_pair
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;


const int N=1e7+10;
const int MAXN=20010;
const int INF=0x3f3f3f3f;
const double eps=0.0000001;
const ll mod=1e9+7;

int a[20]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,51};
ll ans,m,n,x,maxn;

void dfs(ll val,ll pre,ll num,ll flo)//val当前值,pre当前的素数,num约数的个数,flo指数上限
{
    if(num>maxn||num==maxn&&ans>val)
    {
        maxn=num;
        ans=val;
    }
    ll z=1,gcd,now=val;
    while(z<=flo)
    {
        z++;
        if(x/a[pre]<now) break;
        now=now*a[pre];
        gcd=z*num;
        dfs(now,pre+1,gcd,z-1);//指数递减,此次是z,下一次的上限为z-1
    }
}

int main()
{
    ll t;
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld",&x);
        maxn=-1,ans=-1;
        dfs(1,1,1,16);
        printf("%lld\n",maxn);
    }
    //cout << "Hello world!" << endl;
    return 0;
}

华华送奕奕小礼物
题解:
s u m a sum_a suma a a a的前缀和, s u m b sum_b sumb b b b的前缀和。
则以 ( x 1 , y 1 ) (x1,y1) (x1,y1)为左上角,以 ( x 2 , y 2 ) (x2,y2) (x2,y2)为右下角的矩阵的权值为
( s u m a [ x 2 ] − s u m a [ x 1 − 1 ] ) ∗ ( s u m b [ y 2 ] − s u m b [ y 1 − 1 ] ) (sum_a[x2]-sum_a[x1-1])* (sum_b[y2]-sum_b[y1-1]) (suma[x2]suma[x11])(sumb[y2]sumb[y11])
其中要满足 x 1 < = x 2 , y 1 < = y 2 x1<=x2,y1<=y2 x1<=x2,y1<=y2 x 1 , x 2 x1,x2 x1,x2的选择与 y 1 , y 2 y1,y2 y1,y2的选择相互独立。
可以预处理所有 y 1 , y 2 y1,y2 y1,y2的组合,然后排序。接下来枚举 x 1 , x 2 , x1,x2, x1,x2 y y y二分即可。
复杂度 n 2 ∗ l o g ( m 2 ) n ^2*log(m ^2) n2log(m2)

#include<bits/stdc++.h>
#define mp make_pair
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;


const int N=1e7+10;
const int MAXN=20010;
const int INF=0x3f3f3f3f;
const double eps=0.0000001;
const ll mod=1e9+7;
ll n,m,l,r,x,cnt;
ll a[N],b[N],c[N];

ll slove(ll x)
{
    ll ans=0;
    ll l=0,r=cnt-1;
    while(l<=r)
    {
        ll mid=(l+r)/2;
        if(c[mid]<=x)
        {
            ans=mid+1,l=mid+1;
        }
        else
            r=mid-1;
    }
    return ans;
}

ll work(ll x)
{
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<i;j++)
        {
            ans+=slove(x/(a[i]-a[j]));
        }
    }
    return ans;
}

int main()
{
    scanf("%lld%lld%lld%lld",&n,&m,&l,&r);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&x);
        a[i]=a[i-1]+x;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%lld",&x);
        b[i]=b[i-1]+x;
        for(int j=0;j<i;j++)
        {
            c[cnt++]=b[i]-b[j];
        }
    }
    sort(c,c+cnt);
    printf("%lld\n",work(r)-work(l-1));


}

华华跟奕奕玩游戏
题解:大佬的详解
标程:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=1e9+7;
ll pow1(ll a,ll b)
{
    ll r=1;
    while(b)
    {
        if(b&1)
            r=r*a%mod;
        a=a*a%mod;
        b/=2;
    }
    return r;
}
int main()
{
    int n,m,k,a,b;
    scanf("%d%d%d%d%d",&n,&m,&k,&a,&b);
    ll p=1LL*a*pow1(b,mod-2)%mod;
    ll s=1LL*(n+m)*pow1(n+m+1,mod-2)%mod;
    ll ans=1LL*n*pow1(s,k)%mod+p*(s-pow1(s,k+1))%mod*pow1(1-s,mod-2)%mod;
    ans=ans%mod+mod;
    printf("%lld\n",ans%mod);
    return 0;
}

华华陪奕奕打怪兽
题解:二分+贪心
大佬的详细题解

#include<bits/stdc++.h>
#define mp make_pair
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;


const int N=1e7+10;
const int maxn=1e5+10;
const int INF=0x3f3f3f3f;
const double eps=0.0000001;
const ll mod=1e9+7;

int n;
ll C,W;
ll a[maxn],b[maxn];
int num[maxn],tx_num[maxn],id[maxn];///num表示循环次数,tx-num表示副本,id维护第几秒

struct note
{
    ll cost,id;
};

bool operator<(const note &A,const note &B)
{
    return A.cost>B.cost;
}

priority_queue<note>q;

bool slove(ll x)
{
    for(int i=1;i<=min(x,(ll)n);i++)
    {
        note e;
        e.cost=a[i]*b[1];
        num[i]=x/n;
        if(x%n&&i<=x%n)
        {
            num[i]++;
        }
        tx_num[i]=num[i];
        e.id=i;
        id[i]=1;
        q.push(e);
    }
    ll c=C,w=W;
    while(c)
    {
        note fir=q.top();
        c--;
        w-=fir.cost;
        if(w<=0) return 0;
        num[fir.id]--;
        if(num[fir.id]==0)
        {
            id[fir.id]++;
            num[fir.id]=tx_num[fir.id];
            fir.cost=a[fir.id]*b[id[fir.id]];
            q.pop();
            q.push(fir);
        }
    }
    while(!q.empty())
        q.pop();
    return 1;
}

int main()
{
    scanf("%d%lld%lld",&n,&C,&W);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    for(int i=1;i<=C;i++)
        scanf("%lld",&b[i]);
    ll l=1,r=n*C,ans=INF;
    while(l<=r)
    {
        ll mid=(l+r)>>1;
        if(slove(mid))
        {
            ans=mid;
            r=mid-1;
        }
        else
        {
            l=mid+1;
        }
    }
    if(ans==INF) printf("-1\n");
    else
    printf("%lld\n",ans);


}

华华和奕奕学物理
题解:树状数组+公式推导
大佬的详细题解
比较有意思的就是,找到速度小的所有球都是谁,一开始想法很朴素就查询一次然后比较一次,没有想到更好的方法。然后答案给的思路就很优秀了,因为是在线查询所以,查询的肯定为之前抛下去的小球。
所以就可以这样想,已知若某一时刻a球比b球速度快,则a球始终比b球速度快,所以想判断某一时刻的速度大小和判断随机时刻的速度大小没有区别,所以直接撸到底, 在最后时刻时将所有0-V的动能求个和就好了。
所以可以用最终速度V代表数组的下标,那么数组如何维护动能呢,
因为动能仅与查询的时间 t2 相关且二次相关,其余的都是常数,所以公式有三项,也就是可以用V的数组,分别维护三个系数就好了。最后区间求和就可以用各种数据结构维护一下。

#include<bits/stdc++.h>
using namespace std;
const int maxn=4e6+100;
const int T=3e5+10;
const int mod=1e9+7;
const int g=10;
#define ll long long
ll bit[8][maxn];
void add(ll b[],int i,ll C)
{
    while(i<maxn)
    {
        b[i]=(b[i]+C)%mod;
        i+=i&-i;
    }
}
ll sum(ll b[],int i)
{
    ll  ans=0;
    while(i>0)
    {
        ans+=b[i];
        i-=i&-i;
    }
    return ans%mod;
}
int main()
{
    int Q;scanf("%d",&Q);
    while(Q--)
    {
        int op,v,t,m;scanf("%d%d%d",&op,&v,&t);
        if(op==1)
        {
            int V=v+g*(T-t);
            scanf("%d",&m);
            add(bit[1],V,1LL*m*v%mod*v%mod);
            add(bit[2],V,1LL*m*g*g%mod);
            add(bit[3],V,1LL*m*g*g%mod*t%mod*t%mod);
            add(bit[4],V,1LL*2*m*g*g%mod*t%mod);
            add(bit[5],V,1LL*2*m*v%mod*g%mod);
            add(bit[6],V,1LL*2*m*v%mod*g*t%mod);
        }
        else
        {
            int V=min(v+g*(T-t),maxn-1);
            ll ans=0;
            ans+=sum(bit[1],V);
            ans+=sum(bit[2],V)*t%mod*t%mod;
            ans+=sum(bit[3],V);
            ans-=sum(bit[4],V)*t%mod;
            ans+=sum(bit[5],V)*t%mod;
            ans-=sum(bit[6],V);
            ans%=mod;
            if(ans<0)
                ans+=mod;
            printf("%lld\n",ans);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值