noip2011 d2 考试总结

绝望的一早上。

t1杨辉三角,十分钟看出来,二十分钟写完,运行了几个数据过后就没管了。结果爆零!!看了半天才发现数组下标0没有特判。。它爆了!爆了!了!垃圾dev。

#include<iostream>
#include<cstdio>
using namespace std;

#define mod 10007

int qwq[1005][1005];

int main ( ) {
    freopen ( "factor.in", "r", stdin );
    freopen ( "factor.out", "w", stdout );
    int a, b, k, n, m;
    scanf ( "%d%d%d%d%d", &a, &b, &k, &n, &m );
    qwq[0][0] = 1;
    for ( int i = 1; i <= k; i ++ ) {
        for ( int j = 0; j <= i; j ++ ) {
            if ( j == 0 ) qwq[i][j] = 1ll * qwq[i-1][j] * a % mod;
            else if ( i == j ) qwq[i][j] = 1ll * qwq[i-1][j-1] * b % mod;
            else qwq[i][j] = ( 1ll * qwq[i-1][j-1] * b % mod + 1ll * qwq[i-1][j] * a % mod ) % mod;//j=0时j-1是-1qwq
        }
    }       
    printf ( "%d", qwq[k][m] );
    return 0;
}

t2二分+记录前缀和。二分写对了,然后就不想思考了,直接把所有区间for了一遍:) 好吧下次考试不做作业了。

#include<iostream>
#include<cstdio>
using namespace std;

#define ll long long

const int N = 200005;

ll abss ( ll a ) {
    if ( a >= 0 ) return a;
    else return (-1) * a;
}

ll n, m, S, w[N], v[N], L[N], R[N], MAX;
ll pre[N], cnt[N];

ll init ( int W ) {
    ll ans = 0;
    for ( int i = 1; i <= n; i ++ ) {
        if ( w[i] >= W ) { cnt[i] = cnt[i-1] + 1; pre[i] = pre[i-1] + v[i]; }
        else { cnt[i] = cnt[i-1]; pre[i] = pre[i-1]; }
    }
    for ( int i = 1; i <= m; i ++ ) {
        ans += ( cnt[R[i]] - cnt[L[i]-1] ) * ( pre[R[i]] - pre[L[i]-1] );
    }//记录每个区间符合条件的数的个数和价值的前缀和,需要哪段取哪段即可。不是很懂自己当时为什么只想到(n2)循环,
    return ans;
}

ll erfen ( ) {
    ll ans = S; int l = 1, r = MAX+1;
    while ( l <= r ) {
        int mid = (l+r) >> 1;
        ll an = init ( mid );
        if ( an > S ) {
            l = mid+1;
            if ( an-S < ans )
                ans = an-S;
        } else if ( an < S ) {
            r = mid-1;
            if ( S-an < ans )
                ans = S-an;
        } else return 0;
    }
    return ans;
}

int main ( ) {
    freopen ( "qc.in", "r", stdin );
    freopen ( "qc.out", "w", stdout );
    scanf ( "%I64d%I64d%I64d", &n, &m, &S );
    for ( int i = 1; i <= n; i ++ ) {
        scanf ( "%I64d%I64d", &w[i], &v[i] );
        MAX = max ( MAX, w[i] );
    }
    for ( int i = 1; i <= m; i ++ )
        scanf ( "%I64d%I64d", &L[i], &R[i] );
    ll ans = erfen ( );
    printf ( "%I64d", ans );
    return 0;
}

t3贪心(?)。讲完题过后发现自己思路大致都是对的,可是没有深思。取最优的边来优化的部分想的太简单了,取的应该是经过了当前边就到达目的地的人数最多的那条边。

#include<iostream>
#include<cstdio>
#ifdef WIN32
#define ld %I64d
#else
#define ld %lld
#endif

using namespace std;

int n, m, k;
const int N = 10005;

#define ll long long

int d[N], t[N], a[N], b[N], las[N], cnt[N], nex[N], ans, ar[N];

int main ( ) {
    freopen ( "bus.in", "r", stdin );
    freopen ( "bus.out", "w", stdout );
    scanf ( "%d%d%d", &n, &m, &k );
    for ( int i = 1; i < n; i ++ )
        scanf ( "%d", &d[i] );
    for ( int i = 1; i <= m; i ++ ) {
        scanf ( "%d%d%d", &t[i], &a[i], &b[i] );
        las[a[i]] = max ( t[i], las[a[i]] );
        cnt[b[i]] ++;
    }
    for ( int i = 1; i <= n; i ++ )
        cnt[i] += cnt[i-1];
    while ( 1 ) {
        int maxl = 1;
        ar[1] = 0;
        for ( int i = 2; i <= n; i ++ )
            ar[i] = max ( ar[i-1], las[i-1] ) + d[i-1];
        nex[n] = n;
        for ( int i = n-1; i >= 1; i -- ) {
            nex[i] = nex[i+1];
            if ( ar[i+1] <= las[i+1] )
                nex[i] = i + 1;
        }
        while ( !d[maxl] && maxl <= n-1 ) 
            maxl ++;
        if ( maxl == n || k == 0 ) break;//所有边都消完了或者没氮气了
        for ( int i = maxl + 1; i <= n - 1; i ++ )
            if ( d[i] && cnt[nex[maxl]] - cnt[maxl] < cnt[nex[i]] - cnt[i] )
                maxl = i;
        if ( cnt[nex[maxl]] - cnt[maxl] == 0 ) break;//已经不能优惠人了
        int cha = 1000000000;
        for ( int i = maxl + 1; i <= nex[maxl] - 1; i ++ )
            cha = min ( cha, ar[i] - las[i] );
        cha = min ( cha, k );
        cha = min ( cha, d[maxl] );
        k -= cha;
        d[maxl] -= cha;
    }
    for ( int i = 1; i <= m; i ++ )
        ans += ar[b[i]] - t[i];
    cout << ans;
    return 0;
}

最近有点颓,继续努力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值