2- noip模拟赛 DAY2

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NOI(全国青少年信息学奥林匹克竞模拟的测试数据是指用于评测参选手的程序的输入和对应的输出。测试数据是非常重要的,因为它决定了参选手的程序能否正确地解决问题。 在NOI模拟中,测试数据具有以下特点: 1.充分覆盖:测试数据应涵盖各种可能的输入情况,包括边界条件和极端情况。通过提供不同的测试数据,可以考察选手对问题的全面理解和解决能力。 2.随机性和均衡性:为了公平起见,测试数据应该是随机生成的,而不是针对某个特定算法或解法设计的。同时,测试数据应该是均衡的,即各种情况的概率应该大致相等,以避免偏向某些解法。 3.合理性和可行性:测试数据应该是合理和可行的,即符合题目要求的输入数据,并且是选手能够通过编写程序来处理的。测试数据应该考虑到程序的限制和时间复杂度,以充分测试选手的编程能力。 NOI模拟的测试数据通常由经验丰富的考题组负责生成。他们会根据题目的要求和限制,设计出一组合理、充分、随机和均衡的测试数据,以确保参选手的程序在各种情况下都能正确运行,并且能通过性能测试。 总之,测试数据在NOI模拟中起到了至关重要的作用,它既考察了选手对问题的理解和解决能力,又提高了选手编程的技巧和效率。同时,合理和恰当的测试数据也是公平竞的保证,确保每个参选手有相同的机会和条件进行竞争。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值