每日一题QAQ

这两篇博客介绍了如何利用树状数组(C++中的ST表)和前缀和解决数论与动态规划问题。第一篇博客通过CF736D题目,展示了如何在静态数组中用ST表维护gcd信息来解决特定条件下的不等式问题。第二篇博客则通过CF629D题目,利用树状数组求解最大上升子序列和,通过排序和去重避免了离散化步骤。两篇博客都强调了在处理动态序列时,如何优化时间复杂度以避免超时。
摘要由CSDN通过智能技术生成

cf736D
思路:a%m=n同时b%m=n,c%m=n(m>=2)可以推出gcd(a-b,b-c)!=1
可以直接双指针来做,不过可能代码会写出锅
由于数组是静态的不会变化,可以考虑使用st表来维护
代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e5 + 10;
ll c[N], a[N];
ll f[N][65];
int t, n;
void init(int n)
{
    for (int i = 1; i <= n; i++)
        f[i][0] = a[i];
    for (int j = 1; j < log(n) / log(2) + 1; j++)
        for (int i = 1; i + (1 << j) - 1 <= n; i++)
        {
            f[i][j] = __gcd(f[i][j - 1], f[i + (1ll << (j - 1))][j - 1]);
        }
}
ll query(int l, int r)
{
    int len = r - l + 1;
    int k = log(len) / log(2);
    return __gcd(f[l][k], f[r - (1 << k) + 1][k]);
}
int main()
{
    cin >> t;
    while (t--)
    {
        cin >> n;
        for (int i = 1; i <= n; i++)
            a[i] = c[i] = 0;
        for (int i = 0; i <= n; i++)
            for (int j = 0; j < 65; j++)
                f[i][j] = 0;
        for (int i = 1; i <= n; i++)
        {
            cin >> c[i];
        }
        for (int i = 1; i < n; i++)
            a[i] = abs(c[i + 1] - c[i]);
        init(n - 1);
        int ans = 1;
        for (int i = 1, j = 1; i <= n - 1; i++)
        {
            while (j <= i && query(j, i) == 1)
                j++;
            ans = max(ans, i - j + 2);
        }
        cout << ans << endl;
    }
    return 0;
}

cf629D
思路:
从题意中可以读出来,这题让求得是最大上升子序列和,由于我太菜了只会写O(N^2)的丑陋代码,显然tle,然后换了个思路来想,当走到第i个得时候,我们只需要考率i前边比i小的集合里边的最大值,然后就可以转化为前缀区间最大值,可以使用树状数组来维护,注意不要从0开始
由于最后放的时候两个相邻的蛋糕不能一样大,就不需要离散化,只需要排序,去重就ok
代码:

#include<bits/stdc++.h>
#define ll long long
#define pi 3.141592654
using namespace std;
const int N=1e5+10;
ll p[N],c[N],d[N];
int cnt;
int n;
int lowbit(int x)
{
    return x&-x;
}
ll query(int x)
{
    ll res=0;
    while(x)
    {
        res=max(res,p[x]);
        x-=lowbit(x);
    }
    return res;
}
void add(int x,ll val)
{
    while(x<=cnt)
    {
        p[x]=max(p[x],val);
        x+=lowbit(x);
    }
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        ll a,b;
        cin>>a>>b;
        c[i]=d[i]=a*a*b;
    }
    sort(c+1,c+n+1);
    cnt=unique(c+1,c+n+1)-c;
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        int l=1,r=cnt;
        while(l<r)
        {
            int mid=l+r>>1;
            if(c[mid]>d[i]) r=mid;
            else l=mid+1;
        }
        ll res=query(l-1)+d[i];
        ans=max(ans,res);
        add(l,res);
    }
    printf("%.6lf\n",double(ans)*pi);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值