2019/8/3 暑假排位_END

Attempted_简单篇

G题:Power OJ 2868

详解
怎么说呢,做的时候总是觉得自己的思路完全正确,但是就是一直WA。其实就是思路被限制了,然后最后也没过。最后一个小时本来打算把G题和D题过了,但是就是没什么新的思想碰撞,想不到该改哪里,就是觉得自己的没错。还好最后半个小时开了另外一道题给一发过了。

H题:Power OJ 2869

思路:
在这里插入图片描述
My_Feeling:(贼简单的数学解方程QAQ,就做不出来,猜了个答案没过,就没做了,tcl)

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
int main()
{
    ll n;
    while(~scanf("%lld", &n))
    {
        printf("%lld\n", -n);
    }
    return 0;
}

D题:Power OJ 2870

题意:最长上升子序列(单调不下降)模板【详解

思路:时间复杂度要求我们必须控制在O(n * logn)内。但是有所不同的是单调不下降,所以我们要保证可以存在重复的数字,所以说我们的 low 数组就可以存在重复的数字,并且当我们遇到较小的数字时我们要放在 low 数组中第一个大于它的数字的位置上。(必须是不能替代小于等于的数字,否则答案就会偏小)

样例:(用 lower_bound就会错)

6
1 2 5 2 2 2

wrong answer: 3
:)就是直接2每次都覆盖2,所以长度不会变
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxN=1e5+5;
int ans, a[maxN], low[maxN] , n;

void init()
{
    ans = 0;
    memset(low, 0 , sizeof(low));
}

int LIS()
{
    for(int i = 1; i <= n ; i++)
    {
        if( a[i] >= low[ans])
            low[++ans] = a[i];
        else
            low[ upper_bound(low, low + ans + 1, a[i]) - low ] = a[i];
    }
    return ans;
}

int main()
{
    while(~scanf("%d", &n))
    {
        init();
        for(int i = 1; i <= n ; i++)
            scanf("%d", &a[i]);
        printf("%d\n", LIS());
    }
    return 0;
}

Unattempted_简单篇

B题:Power OJ 2867

思路:一道简单的高数题:求极限。如果分子的次幂大,那么为无穷;如果分母的次幂大,那么为0;如果相等那么就等于系数之比。

My_Feeling: 怎么说呢,这道题连看都没有看,看题面就感觉做不了。现在补题的话,还把求和当成求乘积做了。而且开4个longlong的1 e 5,编译器就给我报错QAQ,生气。挺简单的,只用到了一个gcd,其他就没有了。QAQ……

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxN = 1e5 + 5;

ll gcd(ll x, ll y)
{
    return y == 0 ? x : gcd(y, x % y);
}

int main()
{
    int n, m;
    while(~scanf("%d%d", &n, &m))
    {
        ll a[maxN], b[maxN];
        ll up = 0, down = 0;
        ll up_index = 0, down_index = 0;
        for(int i = 0 ; i < n ; i ++ )
        {
            scanf("%lld%lld", &a[i], &b[i]);
            up_index = max( up_index, b[i]);
        }
        for(int i = 0 ; i < n ; i ++)
            if( b[i] == up_index )
                up += a[i];
        for(int i = 0; i < m ; i ++)
        {
            scanf("%lld%lld", &a[i], &b[i]);
            down_index = max(down_index, b[i]);
        }
        for(int i = 0 ; i < m ; i ++)
            if( b[i] == down_index )
                down += a[i];
        if(up_index > down_index)
            printf("Orz\n");
        else if(up_index < down_index)
            printf("0\n");
        else
        {
            ll _gcd = gcd(up, down);
            up /= _gcd;
            down /= _gcd;
            printf("%lld/%lld\n", up, down);
        }
    }
    return 0;
}

C题:Power OJ 2866

官方题面:现在有一个字符串s我们称为文本串。然后给出m个字符串,这m个字符串我们称为模式串。对于每一个模式串t,我们用p表示在s中有多少个前缀的后缀中出现了t,我们用q表示在s中有多少个后缀的前缀中出现了t。他现在想知道p和q中的最大值。

【读了之后感觉……???这是什么鬼】

我最初理解的题意:p:多少个前缀中出现了模式串。q:多少个后缀中出现了模式串。取其中的较大者。

实际的题意:文本串中有多少个模式串。

【惊不惊喜?!意不意外?!】

实际上题面中的那个出现是:前缀的后缀中有一个后缀是模式串,后缀的前缀中有一个前缀是模式串,那么这样的话,p和q总是相同。也就是找文本串中有多少个模式串。

【说是简单题叭,但是卡了题面QAQ,我是比赛的时候也没读懂,比赛后也没读懂,还是问了人】

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxN = 2e3 + 5;

int main()
{
    char s[maxN];
    while(~scanf("%s", s))
    {
        int len = strlen(s);
        int m; scanf("%d", &m);
        while(m -- )
        {
            char tmp[maxN];
            scanf("%s", tmp);
            int tlen = strlen(tmp);
            int ans = 0;
            for(int i = 0; i < len ; i++)
            {
                if(s[i] == tmp[0])
                {
                    int j = 0;
                    for( ; j < tlen ; j ++)
                    {
                        if(s[i + j] == tmp[j])
                            continue;
                        break;
                    }
                    if(j == tlen)
                        ans++;
                }
            }
            printf("%d\n", ans);
        }
    }
    return 0;
}

AC篇

A题:Power OJ 2874

题意:按规则输出一个三角形

思路:直接看代码叭

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <list>
#include <map>
#define INF 0x3f3f3f3f
#define MID l + r >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
 
using namespace std;
typedef long long ll;
typedef vector<int>:: iterator VITer;
const ll maxN=1e5+5;
 
int main()
{
    int T; scanf("%d", &T);
    while(T--)
    {
        int N; scanf("%d", &N);
        if( N == 0)
            continue;
        if(N == 1)
        {
            printf("*\n");
            continue;
        }
        //第一行
        int tmp = N - 1;
        while(tmp -- )
            putchar(' ');
        printf("*\n");
        //中间
        for(int i = N-1 ; i > 1 ; i -- )
        {
            tmp = i - 1;
            while(tmp -- )
                putchar(' ');
            printf("*");
            for(int j = 1; j < 2*(N - i) ; j ++)
                putchar(' ');
            printf("*\n");
        }
        //最后一行
        tmp = N + N -1;
        while(tmp--)
            putchar('*');
        printf("\n");
    }
    return 0;
}

E题:Power OJ 2864

题意:可以跳2 ~ k 层的倍数层,那么2 ~ n层楼不能到达的楼层数最大是多少。

思路:由于数据很大,所以用不了暴力。我们知道相邻两个质数相差是不大的,(悄悄咪咪地:听学长说不超过100),所以我的做法就是:首先我们知道质数是一定不会被跳到的,除非这个质数<=k。所以我们找到n内最大的质数(倒着找,快),然后从这个质数跑到n是外层循环,内层是1e6的循环(其实也跑不了那么多),也就是1e6乘以一个大常数,所以时间复杂度完全可以。
需要注意的就是当最大质数可以被跳到,也就是说是p之内的数的时候,tmp就更新为1,输出为1嘛,全部可以跳到的时候。这时候我们不用担心剩余的楼层不会被跳到,因为我们输出的是tmp和ans中的较大者,不会被跳到的楼层我们是用ans来存最大值的。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <list>
#include <map>
#define INF 0x3f3f3f3f
#define MID l + r >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
 
using namespace std;
typedef long long ll;
typedef vector<int>:: iterator VITer;
const int maxN=1e6+5;
const int maxE = 1e4 +5;
 
int prime[maxN], vis[maxN], cnt;
 
void init()
{
    memset(prime, 0, sizeof(prime));
    memset(vis, 0, sizeof(vis));
    vis[0] = 1;
    vis[1] = 1;
    cnt = 0;
}
 
void Prime()
{
    init();
    for(int i = 2; i <= 1e6 ; i++)
    {
        if(! vis[i])
            prime[ ++ cnt] = i;
        for(int j = 1 ; j <= cnt ; j++)
        {
            if(prime[j] * i > 1e6) break;
            vis[prime[j] * i] = 1;
            if(i % prime[j] == 0) break;
        }
    }
}

int main()
{
    Prime();
    int p, n;
    int T; scanf("%d", &T);
    while(T--)
    {
        int tmp = 1;
        scanf("%d%d", &p, &n);
        for(int i = n ; i > 0 ; i--)
            if(!vis[i])
            {
                tmp = i;
                break;
            }
        int ans = 1;
        for(int i = tmp; i <= n ; i++)
        {
            int flag = 0;
            for(int j = 2 ; j <= p ; j++)
            {
                if(i % j == 0)
                {
                    flag = 1;
                    break;
                }
            }
            if(i == tmp && flag)
                tmp = 1;
            if(!flag)
                ans = i;
        }
        printf("%d\n", max(tmp, ans));
    }
    return 0;
}

F题:Power OJ 2865

题意:我们打两个不同血量的怪兽,最短的天数是多少。

思路:首先的话我们打一个怪兽,总是有一个血量少的,一个血量大的,或者两个怪兽血量相同。所以我们总能找到和血量较少的相同的伤害值的那天,所以我们就直接将两者血量相加变成一个超级大怪兽,然后能够打死它的那天就可以了。因为数据比较大,所以我们用到二分

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <list>
#include <map>
#define INF 0x3f3f3f3f
#define MID l + r >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
 
using namespace std;
typedef long long ll;
typedef vector<int>:: iterator VITer;
const ll maxN = 7e4+5;
 
ll minn, maxx;
 
bool judge(ll x)
{
    return x * (x + 1) / 2 >= maxx;
}
 
int main()
{
    ll A, B;
    while(~scanf("%lld%lld", &A, &B) && (A || B))
    {
        maxx= A + B;
        if( maxx == 1)
        {
            printf("1\n");
            continue;
        }
        ll ans;
        ll l = 0, r = maxN, mid;
        while(l < r)
        {
            mid = (l + r) / 2;
            if(judge(mid))
            {
                r = mid;
                ans = mid;
            }
            else
                l = mid +1;
        }
        printf("%lld\n", ans);
    }
    return 0;
}

J题:Power OJ 2872

题意:【最短路】求起点到终点的路费最小值。有两种优惠:(1)每条道路免费 (2)在给定的可免费的道路中任选一条免费。(可不选择优惠)

思路:肯定要用优惠啊,不用优惠那肯定贵。

第(1)种优惠:直接求出最短路,然后取一半的值即可。

第(2)种优惠:那么我们如何保证只选择一条道路免费呢?首先我们用二维dis[ ]来维护各点到起点以及各点到终点的最短路。然后我们遍历一遍可免费的道路,如果用上这条路的免费比之前的最短路更优,那么我们就更新dis 。其余的话就是最短路模板了。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <list>
#include <map>
#define INF 0x3f3f3f3f
#define MID l + r >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
 
using namespace std;
typedef long long ll;
typedef vector<int>:: iterator VITer;
const int maxV=1e3+5;
const int maxE = 1e4 +5;
int n, m, s, e;
int head[maxV], cnt;
void init()
{
    memset(head, -1 , sizeof(head));
    cnt = 0;
}
 
struct EDGE{
    int pre,from, to, w;
    EDGE(int a = 0, int b = 0, int c = 0, int d= 0) : pre(a),from(b), to(c), w(d){}
}edge[maxE << 1];
 
void add_edge(int u, int v, int val)
{
    edge[++cnt] = EDGE(head[u], u, v, val);
    head[u] = cnt;
}
 
struct node{
    int point, val;
    node(int a= 0, int b = 0) : point(a), val(b){}
    friend bool operator < (node n1, node n2) { return n1.val > n2.val; }
};
 
int vis[maxV], dis[2][maxV];
 
void dij(int st,int mark)
{
    memset(vis, 0, sizeof(vis));
    for(int i = 1; i <= n ; i++ )
        dis[mark][i] = (i == st ? 0 : INF);
    priority_queue<node> pq;
    pq.push(node(st, dis[mark][st]));
    while(!pq.empty())
    {
        node tmp = pq.top();
        pq.pop();
        if(vis[tmp.point])
            continue;
        for(int i = head[tmp.point]; ~i ; i = edge[i].pre)
        {
            if(dis[mark][edge[i].to] > dis[mark][tmp.point] + edge[i].w)
            {
                dis[mark][edge[i].to] = dis[mark][tmp.point] + edge[i].w;
                pq.push(node(edge[i].to, dis[mark][edge[i].to]));
            }
        }
        vis[tmp.point] = 1;
    }
}
 
int main()
{
    while(~scanf("%d%d%d%d", &n, &m, &s, &e))
    {
        init();
        for(int i = 1; i <= m; i++)
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            add_edge(a, b, c);
            add_edge(b, a, c);
        }
        dij(s, 0);
        dij(e, 1);
        int tmp = dis[0][e] / 2;
        int k; scanf("%d", &k);
        for(int i = 1 ; i <= k ; i ++)
        {
            int num; scanf("%d", &num);
            num *= 2;
            if(dis[0][e] > dis[0][edge[num].from] + dis[1][edge[num].to])
            {
                dis[0][e] = dis[0][edge[num].from] + dis[1][edge[num].to];
            }
            else if(dis[0][e] > dis[1][edge[num].from] + dis[0][edge[num].to])
            {
                dis[0][e] = dis[1][edge[num].from] + dis[0][edge[num].to];
            }
        }
        if(dis[0][e] == INF)
            printf("-1\n");
        else
            printf("%d\n",min(dis[0][e], tmp));
    }
    return 0;
}

Attempted_线段树

Power OJ 2873

题意:区间翻转更新,区间查询【这里的翻转是每一个数值二进制按位异或后得到的新的数值】

思路:就是翻转操作不太好弄叭。0按位翻转就是INT32_MAX,那么1翻转是什么呢?我们可以发现是INT32_MAX - 1. 那么2翻转是什么呢?是INT32_MAX - 2. 知道了这个我们就可以直接来敲线段树了。

当时敲了之后发现虽然区间和是m,但是如果有多个0进行翻转的话,那么我的操作就是不对的,因为我是直接INT32_MAX - 区间和就是更新的值了。当时想新开一个zero的数组来存0的个数,但是怎么想怎么没办法处理。QAQ
后来听了出题人的讲解就是只需要把INT32_MAX * 区间长度然后再 - 区间和即可。
听了之后……哭辽

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <list>
#include <map>
#define INF 0x3f3f3f3f
#define MID l + r >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr

using namespace std;
typedef long long ll;
const ll maxN=1e5+5;

ll num[maxN];
ll tree[maxN << 2], lazy[maxN << 2];

void pushup(ll rt) { tree[rt] = tree[lsn] + tree[rsn]; return ; }

void build_tree(ll rt, ll l, ll r)
{
    if( l == r ) { tree[rt] = num[l]; return ; }
    ll mid = MID;
    build_tree(Lson);
    build_tree(Rson);
    pushup(rt);
}

void pushdown(ll rt, ll l, ll r)
{
    if(lazy[rt])
    {
        ll mid = MID;
        tree[lsn] = INT32_MAX * (mid - l +1) - tree[lsn];
        tree[rsn] = INT32_MAX * (r - mid) - tree[rsn];
        lazy[lsn] = lazy[lsn] ^ 1;
        lazy[rsn] = lazy[rsn] ^ 1;
        lazy[rt] = 0;
    }
}

void update_range(ll rt, ll l, ll r, ll ql , ll qr)
{
    if( ql <= l && qr >= r)
    {
        tree[rt] = INT32_MAX * (r - l + 1) - tree[rt];
        lazy[rt] ^= 1;
        return ;
    }
    pushdown(rt, l, r);
    ll mid = MID;
    if(qr <= mid) update_range(QL);
    else if( ql > mid) update_range(QR);
    else { update_range(QL); update_range(QR); }
    pushup(rt);
}

ll query(ll rt, ll l, ll r, ll ql, ll qr)
{
    if(ql <= l && qr >= r) { return tree[rt]; }
    pushdown(rt, l, r);
    ll mid = MID;
    if( qr <= mid) return query(QL);
    else if(ql > mid) return query(QR);
    else return query(QL) + query(QR);
}

void init()
{
    memset(lazy, 0, sizeof(lazy));
}

int main()
{
    ll N, Q;
    while(~scanf("%lld%lld", &N, &Q))
    {
        init();
        for(ll i = 1 ; i <= N; i ++)
        {
            scanf("%lld", &num[i]);
        }
        build_tree(1, 1, N);
        char s[10];
        while(Q--)
        {
            scanf("%s", s);
            ll a, b; scanf("%lld%lld", &a, &b );
            if(s[0] == 'C')
                update_range(1, 1, N, a, b);
            else if(s[0] == 'Q')
                printf("%lld\n", query(1, 1, N, a, b));
        }
    }
    return 0;
}

Unattempted_字典树

I题:Power OJ 2871

详解

Summary:

最后的比赛就4题,最后的时间基本就开不出题,很乱,也看不下去题意。尤其是看见大佬们chua chua 的过题,就一连好几道题就更着急了。其实也没有多么多么地着急但是还是会影响心态的。而且有些题限制的思路就怎么都想不到差了那么一点的正解。

很惭愧就是放了好几天假了才补起来题,然后还有就是真的很佩服几个同学,前几道题,被归为简单的题,这种做的很快,思路很快叭。ORZ,我呢就是虽然是简单题还是做不出来。我就是那种明明很菜有的时候还老是没有人家努力。

这一个月来其实很多时候都在划水,不是我想这样的,我也不想,但是我就是没办法找到自己的状态。超级烦躁,想哭,也哭过很多次,看别人状态很好就觉得自己超级……自愧不如叭。队长讲话的时候说:有些同学就只做一些模板题,有些就是补完了,一下就是十几道题的差距,题的难度还不一样,人家做的多还都是难题。我就是这样的叭。很多时候没有状态去做题,然后最后一周复习,人家都在补题的时候我也补不了题,因为一直在看从来没有怎么看过的数论。

但是我倒是不会因为他的这些话怎么样,自己有自己的想法和计划。我是想先什么都涉猎了熟悉了再来刷题,我的时间精力浪费了很多,但是会之后慢慢补回来培训比人家落下的。

回家了这么多天,发生了挺多事情的,心情也是很纠结很起伏。希望我可以坚持下去,也快回学校了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值