2- noip模拟赛 DAY2

来源:互联网 发布:淘宝购物的流程 编辑:程序博客网 时间:2024/05/16 09:59

T1 勾股数

因为a2=c2b2,所以可以用平方差公式展开,a2=(cb)(c+b)
分情况考虑:
当输入的a为奇数时,
cb=1,则c+b=a2,所以2b+1=a2,解得:

{b=a212c=a212+1

当输入的a为偶数时
cb=2,则c+b=a22,所以2b+2=a22,解得:
b=a241c=a24+1

    #include <iostream>    #include <cstdio>    using namespace std;    typedef long long ll;    int main(){        ll a;        cin >> a;        if(a<=2) cout << "-1";        else if(a&1) cout << (a*a-1)/2 << " " << ((a*a-1)/2)+1;        else cout << (a*a)/4-1 << " " << ((a*a)/4)+1;        return 0;    }

T2 区间和

先将原问题转化为b序列前k小的元素的和。由于数列中每个数的都大于零,所以可以二分b序列第k小的元素的大小。给定x,求b序列中小于等于x的元素个数有两种方法:1.枚举a的区间的左端点l(一共有n个),然后再一次二分,求出最右的右端点r使得ri=la[i]x,复杂度O(nlogn);2.一次dp求出所有左端点对应的右端点,复杂度O(n)。最后复杂度还要乘上二分的复杂度O(logn)

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long ll;ll n, m, val, num;ll a1[100010], sum[100010], summ[100010];void check(ll x){    ll p = 0;    for(ll i = 1; i <= n; i ++){        p = max(p, i-1);        while(p+1 <= n && sum[p+1] - sum[i-1] <= x) p ++;        val += (summ[p] - summ[i-1] - (p-i+1)*sum[i-1]);        num += (p-i+1);    }}ll solve(ll x){    ll l = 0, r = 1e7, ans = 0, res = 0, cnt = 0;    while(l <= r){        ll mid = (l+r) >> 1;        val = 0, num = 0, check(mid);        if(num >= x) r = mid - 1, ans = mid, res = val, cnt = num;        else l = mid + 1;     }    return res - (cnt-x) * ans;}int main(){    freopen("sum.in", "r", stdin);    freopen("sum.out", "w", stdout);    scanf("%lld%lld", &n, &m);    for(ll i = 1; i <= n; i ++) scanf("%lld", &a1[i]);    for(ll i = 1; i <= n; i ++) sum[i] = sum[i-1] + a1[i], summ[i] = summ[i-1] + sum[i];    for(ll i = 1; i <= m; i ++){        ll a, b;        scanf("%lld%lld", &a, &b);        printf("%lld\n", solve(b) - solve(a-1));    }    return 0;} 

T3 最长上升子序列

0可以转化成任意整数,包括负数,显然求LIS时尽量把0都放进去必定是正确的。因此我们可以把0拿出来,对剩下的做O(nlogn)的LIS,统计结果的时候再算上0的数量。为了保证严格递增,我们可以将每个权值a[i]减去i前面0的个数,再做LIS,就能保证结果是严格递增的。

#include <iostream>#include <cstdio>using namespace std;typedef long long ll;const int inf = 1e9;int f[100010], d[100010], a1[100010];int n, cnt, ans;inline int read(){    char c;    int ok = 0, num = 0;    while(c = getchar()){        if(c <= '9' && c >= '0')             ok = 1, num = num*10+c-'0';        else if(ok) return num;    }}inline int find(int l, int r, int val){    int ans1 = 0;    while(l <= r){        int mid = (l+r)>>1;        if(d[mid] >= val) r = mid-1;        else ans1 = mid,l = mid+1;    }    return ans1;}int main(){    scanf("%d", &n);    for(int i = 1; i <= n; i ++) d[i] = inf; d[0] = -inf;    for(int i = 1; i <= n; i ++) a1[i] = read();    for(int i = 1; i <= n; i ++){        if(a1[i] == 0){            d[ans+1] = d[ans]+1;            for(int j = ans; j >= 1; j --)                if(d[j] > d[j-1]+1)                    d[j] = d[j-1]+1;            f[i] = ++ ans;            continue;        }        f[i] = find(0,i-1,a1[i])+1;        if(a1[i] < d[f[i]]) d[f[i]] = a1[i];        if(f[i] > ans) ans = f[i];    }    printf("%d", ans);    return 0;}
1 0
原创粉丝点击