Astar Round2A

放在前面的..

傻逼呵呵蒟蒻没事做百度之星..


比赛感悟啦啦啦..

这比赛和HWizard一起做啊…

一开始服务器爆炸.. 一直登不上去.. 我tm就是可以上,还傻逼呵呵的给UOJ群发题目

直到大家都可以上的时候才开始做,一看ranklist,在群上一言不发的吉司机早已做了一题.. 而且还有很多人都做了第一题.. 开始看题0.0..

啊第一题什么.. 啊第二题什么.. 啊.. 真的是too naive啊.. 一题都不会做啊..

然后HWizard大神突然爆出一句,啊第一题不是矩乘吗?然后傻逼的我恍然大悟,开始码代码.. 打出来又调啊调.. 最后发现转移矩阵输反了又改改改.. 好吧A了..

然而大神还在狂TLE不止.. 我就去看了比较多人AC的1006,在纸上画了画,又画了画.. 哎这不是拓扑图吗?看看优先级.. 这不是很水吗..

随手来了一发n^2的做法.. 很成功TLE了..

改了个堆优化做法.. 很成功WA了..

再改了个long long.. 很成功AC了..

突然想起某神犇说的【OI成绩=实力+经验..】 真的是too naive啊..

接着就看1002啊,明显的状态压缩..想到一个做法.. 但是被HWizard打消了..然后就没打.. 那么就打1005咯.. 哎这规律有点明显诶.. 码代码0.0..

一次WA.. 两次WA.. 哎快结束了.. 然而考完试的la1la1la看了一下,这1003不是大水题吗?这不是裸题吗?我一看,卧槽这么水的我怎么没看这道题啊..

5min.. 算了放弃0.0..

非常好的拿了个rank610.. 明天再打咯.. too navie啊..

傻逼呵呵的我还涨了170+的rating.. 基础分太低了..


题解一发..

1001
用矩阵乘法求出这个数.. 然后再检验是否符合条件就好了..

code

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
struct node {
    int a[2][2];
    int l1, l2;
    node (){
        memset ( a, 0, sizeof (a) );
    }
}trans, x, z, one;
int X, m, c, K;
node ttimes ( node x, node y ){
    node ret;
    ret.l1 = x.l1; ret.l2 = y.l2;
    int i, j, k;
    for ( i = 0; i <= ret.l1; i ++ ){
        for ( j = 0; j <= ret.l2; j ++ ){
            for ( k = 0; k <= x.l2; k ++ ){
                ret.a[i][j] = ( ret.a[i][j] + (x.a[i][k]*y.a[k][j])%K ) % K;
            }
        }
    }
    return ret;
}
int main (){
    int i, j;
    int T, Ti;
    Ti = 0;
    trans.l1 = trans.l2 = 1;
    trans.a[0][0] = 10; trans.a[0][1] = 0;
    trans.a[1][0] = 1; trans.a[1][1] = 1;
    one.l1 = one.l2 = 1;
    one.a[0][0] = 1; one.a[0][1] = 0;
    one.a[1][0] = 0; one.a[1][1] = 1;
    scanf ( "%d", &T );
    while ( T -- ){
        scanf ( "%d%d%d%d", &X, &m, &K, &c );
        x = trans;
        z = one;
        node p;
        p.l1 = 0; p.l2 = 1;
        p.a[0][0] = 0; p.a[0][1] = X;
        for ( i = m; i >= 1; i >>= 1 ){
            if ( i & 1 ) z = ttimes ( z, x );
            x = ttimes ( x, x );
        }
        p = ttimes ( p, z );
        printf ( "Case #%d:\n", ++Ti );
        if ( p.a[0][0] % K == c ) printf ( "Yes\n" ); 
        else printf ( "No\n" );
    }
    return 0;
}

1002
用f[i][j][k]表示第i个数,前一个数是j,可以选的数的集合状态k,然后就递推啦啦啦..

1003
从0开始,就把0作根拉成一棵树.. 因为要经过x,所以我们可以到达所有x子树上的点.. 那么就裸的dfs序+线段树维护个最大值即可.. 注意防爆栈..

1004
神奇的题目,我现在还没看过题..

1005
s1=B
s2=BBD
s3=BBDBBDD
s4=BBDBBDDBBBDDBDD
看一下s3和s4
s3=BBDBBDD
s4=|BBDBBDD|B|BBDDBDD|
=s3|B|BBD|D|BDD|
=s3|B|s2|D|B|D|D|
=s3|B|s2|D|s1|D|D|
其实再推多几个就可以发现其实可以分成若干个上串.. 而且除了这些串绝对没有别的B.. 那么就一个个2的几次方减一下再累加一下.. 最后再加1就好了..
由于我WA了.. 真的不知道这个做法是不是正确的..

1006
就tm是个拓扑图..
我们可以看出这个队列答案数组是单调不上升的.. 那么假如对于两个数,我可以把它们两个互换位置的话,那肯定是大的在前面.. 记住要long long啊..

code

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#define LL long long
using namespace std;
const LL Maxn = 110000;
LL ind[Maxn], n, m;
struct node {
    LL y, next;
}a[Maxn]; LL first[Maxn], len;
void ins ( LL x, LL y ){
    len ++;
    a[len].y = y;
    a[len].next = first[x]; first[x] = len;
}
bool v[Maxn];
LL _min ( LL x, LL y ){ return x < y ? x : y; }
priority_queue <LL> q;
int main (){
    LL i, j, k, T;
    scanf ( "%I64d", &T );
    while ( T -- ){
        scanf ( "%I64d%I64d", &n, &m );
        memset ( ind, 0, sizeof (ind) );
        len = 0; memset ( first, 0, sizeof (first) );
        for ( i = 1; i <= m; i ++ ){
            LL x, y;
            scanf ( "%I64d%I64d", &x, &y );
            ins ( x, y ); ind[y] ++;
        }
        for ( i = 1; i <= n; i ++ ){
            if ( ind[i] == 0 ) q.push (i);
        }
        LL ans = 0;
        memset ( v, false, sizeof (v) );
        LL minn = n;
        for ( i = 1; i <= n; i ++ ){
            LL p = q.top (); q.pop ();
            v[p] = true;
            minn = _min ( minn, p );
            ans += minn;
            for ( k = first[p]; k; k = a[k].next ){
                LL y = a[k].y;
                ind[y] --;
                if ( ind[y] == 0 ) q.push (y);
            }
        }
        printf ( "%I64d\n", ans );
    }
    return 0;
}

最后再说几句

由于比赛经验真的不够.. 很多细节的东西还是没注意到导致罚时爆炸..

还是要努力训练啊..

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值