noip2016 d2 考试总结

7 篇文章 0 订阅
4 篇文章 0 订阅

非常绝望的一次测试。早上状态很不好呀,t1卡了一个多小时没想出正解,后面就慌了。
以此博客纪念一下这次悲伤的考试。

t1 组合数问题

实际上就是杨辉三角做dp,先预处理出组合数,mod k防止爆掉,然后用相同的三角形结构更新dp值,dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1],如果组合数mod k的值等于0,就++.


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

int yh[2005][2005], dp[2005][2005];

int main ( ) {
    freopen ( "problem.in", "r", stdin );
    freopen ( "problem.out", "w", stdout );
    int t, k;
    scanf ( "%d%d", &t, &k );
    for ( int i = 0; i <= 2000; i ++ )
        for ( int j = 0; j <= i; j ++ )
            if ( j == 0 || j == i || i == 0 ) yh[i][j] = 1;
            else yh[i][j] = (yh[i-1][j]+yh[i-1][j-1])%k;
    for ( int i = 0; i <= 2000; i ++ )
        for ( int j = 0; j <= 2000; j ++ ) {
            dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1];
            if ( j > i ) continue;
            if ( yh[i][j] == 0 ) dp[i][j] ++;
        }
    for ( int kk = 1; kk <= t; kk ++ ) {
        int n, m;
        scanf ( "%d%d", &n, &m );
        printf ( "%d\n", dp[n][min(n,m)] );
    }
}

t2 蚯蚓

三个不上升序列,第一个存原始蚯蚓长度,第二个存切后xq,第三个存x-xq,先sort一边q1,每次取三个队列队首切,切了后推入第二、三个队列,可以证明二三序列一定不上升。
但是q2、q3的h2、h3和h1不一样,h1存的是q1队首,h2、h3存q1、q2队首的前一项,因此判断队空是h2

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

#define ll long long

const int N = 7000005;

ll q1[N], q2[N], q3[N], h1, h2, h3, t2, t3, t1;

bool cmp ( const ll &a, const ll &b ) {
    return a > b;
}

int judge ( ) {
    int ans = 0;
    ll ma = -1301231123;
    if ( h1 <= t1 ) ans = 1, ma = q1[h1];
    if ( h2 < t2 && q2[h2+1] > ma) ans = 2, ma = q2[h2+1];
    if ( h3 < t3 && q3[h3+1] > ma ) ans = 3, ma = q3[h3+1];//h2h3要加一
    return ans;
}

int main ( ) {
    freopen ( "earthworm.in", "r", stdin );
    freopen ( "earthworm.out", "w", stdout );
    int n, m, q, u, v, t;
    scanf ( "%d%d%d%d%d%d", &n, &m, &q, &u, &v, &t );
    for ( int i = 1; i <= n; i ++ )
        scanf ( "%lld", &q1[i] );
    sort ( q1+1, q1+1+n, cmp );
    h1 = 1; t1 = n;
    for ( int i = 1; i <= m; i ++ ) {
        ll a;
        int xx = judge ( );
        if ( xx == 1 ) { a = q1[h1]; h1 ++; }
        else if ( xx == 2 ) { a = q2[h2+1]; h2 ++; }
        else if ( xx == 3 ) { a = q3[h3+1]; h3 ++; }
        a = a + (i-1)*q;
        if ( i % t == 0 ) printf ( "%lld ", a );
        ll x = a*u/v; ll y = a-x;
        q2[++t2] = x-i*q;
        q3[++t3] = y-i*q;//相当于标记了每次切的蚯蚓
    }
    printf ( "\n" );
    for ( int i = 1; i <= n+m; i ++ ) {
        ll a;
        int x = judge ( );
        if ( x == 1 ) { a = q1[h1]; h1 ++; }
        else if ( x == 2 ) { a = q2[h2+1]; h2 ++; }
        else if ( x == 3 ) { a = q3[h3+1]; h3 ++; }
        a = a + m*q;//最后一起加上理应加的总时间,如果被切过k次实际加上的是(m-k)*q.
        if ( i % t == 0 ) printf ( "%lld ", a );
    }
    return 0;
}

t3 愤怒的小鸟

做过的一道状压dp!!可是还是爆零了!!!
有点小难受。。
先预处理出任意两点抛物线能打到的猪猪,状压存储。再遍历所有当前状态,更新加上能打到的猪猪后的状态。注意处理浮点数精度。


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

double x[20], y[20];
int dp[1<<18+1], f[20][20];

bool check ( int i, double a, double b ) {
    double xx = x[i], yy = y[i];
    if ( abs (xx * xx * a + xx * b - yy) < 1e-6 ) return true;
    return false;
}

int main ( ) {
    freopen ( "angrybirds.in", "r", stdin );
    freopen ( "angrybirds.out", "w", stdout );
    int T;
    scanf ( "%d", &T );
    while ( T-- ) {
        int n, m;
        memset ( dp, 0x3f3f3f3f, sizeof ( dp ) );
        memset ( f, 0, sizeof ( f ) );
        scanf ( "%d%d", &n, &m );
        for ( int i = 1; i <= n; i ++ )
            scanf ( "%lf%lf", &x[i], &y[i] );
        for ( int i = 1; i <= n; i ++ )
            for ( int j = 1; j <= n; j ++ ) {
                double x1 = x[i], x2 = x[j], y1 = y[i], y2 = y[j];
                double xx1 = x1*x1, xx2 = x2*x2;
                double b = (y1*xx2-y2*xx1)/(x1*xx2-x2*xx1);
                double a = (y1-b*x1)/xx1;
                if ( a >= 0 ) continue;
                for ( int k = 1; k <= n; k ++ )
                    if ( check ( k, a, b ) )
                        f[i][j] = f[i][j] | (1<<(k-1));
            }
        for ( int i = 1; i <= n; i ++ )
            f[i][i] = 1<<(i-1);
        dp[0] = 0;
        for ( int i = 1; i <= n; i ++ )
            for ( int j = 1; j <= n; j ++ )
                for ( int s = 0; s < (1<<n); s ++ )
                    if ( dp[s|f[i][j]] > dp[s] + 1 )
                        dp[s|f[i][j]] = dp[s] + 1;
        printf ( "%d\n", dp[(1<<n)-1] );
    }
    return 0;
}

可是有dalao用搜索搞出来了!!据说还比状压快!!%%%


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>

#define mem(a, b)  memset (a, b, sizeof(a))
#define dd double

using namespace std;

const int N = 45;
const dd pd = 1e-10;

int T, n, m, ans, q[N];
dd fc[N][2];
bool vis[N];

struct point {
    dd x;
    dd y;
}a[N];

const bool cmp (point aa, point bb)  {
    if (aa.x == bb.x)  return aa.y < bb.y;
    return aa.x < bb.x;
}

dd abss (dd a)  {
    if (a < 0)  a = -a;
    return a;
}

void dfs (int x, int num1, int num2, int use)  {
    if (x == n + 1)  {
        if (use < ans)  ans = use;
        return ;
    }
    if (use >= ans)  return;
    dd yy;
    for (int i = 1; i <= num2; i++)  {
        yy = a[x].x * a[x].x * fc[i][0] + fc[i][1] * a[x].x;
        if (abss(yy - a[x].y) <= pd)  {
            dfs (x + 1, num1, num2, use);
            return ;
        }
    }
    int now, nxt = num2 + 1;
    dd xx, cc;
    for (int i = 1; i <= num1; i++)  {
        if (vis[i])  continue;
        now = q[i];
        if (a[now].x == a[x].x)  continue;
        xx = a[now].x * a[now].x - a[now].x *a[x].x;
        cc = a[now].y - a[x].y * a[now].x / a[x].x;
        fc[nxt][0] = cc / xx;
        if (fc[nxt][0] >= -pd)  continue; 
        fc[nxt][1] = (a[now].y - fc[nxt][0] * a[now].x * a[now].x) / a[now].x;
        vis[i] = 1;
        dfs (x + 1, num1, nxt, use);
        vis[i] = 0;
    }

    q[num1 + 1] = x;
    vis[num1 + 1] = 0;
    dfs (x + 1, num1 + 1, num2, use + 1);
}

int main ()  {
    freopen ("angrybirds.in", "r", stdin);
    freopen ("angrybirds.out", "w", stdout);

    scanf ("%d", &T);
    for (int U = 1; U <= T; U++)  {
        scanf ("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)  {
            scanf ("%lf%lf", &a[i].x, &a[i].y);
        }   
        sort (a + 1, a + n + 1, cmp);
        mem (vis, 0);
        mem (fc, 0);
        mem (q, 0);
        q[1] = 1;
        if (m != 1)  ans = n;
        else  {
            ans = n / 3;
            if (n % 3 != 0)  ans++;
            ans++;
        }
        dfs (2, 1, 0, 1);
        printf ("%d\n", ans);
    }
    return 0;
}

下个星期要翻身!!继续努力!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值