8.4 纪中集训 Day4

T1数列变换

Description

小X 看到堆成山的数列作业十分头疼,希望聪明的你来帮帮他。考虑数列A=[A1,A2,...,An],定义变换f(A,k)=[A2,A3,,,,.Ak,A1,Ak+2,Ak+3,,,,A2k,Ak+1,...],也就是把a 分段,每段k 个(最后如果不足k 个,全部分到新的一段里,见样例),然后将每段的第一个移动到该段的最后一个。

现在,小 X想知道 f (f (f (f ([1,2,3,⋯,n],2),3),⋯),n)的结果。

Input

输入一行包含一个整数n 。

Output

输出一行包含n 个整数,表示最终的数列。

Sample Input

4

Sample Output

4 2 3 1
【样例说明】
f ([1,2,3,4],2) = [2,1,4,3]
f ([2,1,4,3],3) = [1,4,2,3](3单独被分在一组,移动到组的最后一位,仍然是3)
f ([1,4,2,3],4) = [4,2,3,1]

Data Constraint

对于60%的数据,1≤ n ≤10^3。

对于100%的数据,1≤ n ≤10^6。

考场思路/正解

好吧,其实这题我打过,就在来纪中的前一天,不过那时候没有做出来,事后也没有看题解,不过今天在考场上却很愉快地打出来了。

题目讲的很清楚,纯模拟只能得60分(其实已经很高惹,知足吧),但是我们仔细分析题目,不难发现,其实我们只要将要移动的值移到数组末尾就可以了,不需要将其它元素向前移,这样我们也只要开2n的空间就可以了。

Code

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

int n,zx,root=1,k;
int sz[3000030];

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        sz[i]=i;
    for(int i=2;i<=n;i++)
    {
        zx=i-1;
        k=sz[zx];
        while(zx<=n+i-2)
        {
            zx+=i;
            if(zx>n+i-2)
                zx=n+i-1;
            swap(sz[zx],k);
        }
    }
    for(int i=n;i<=2*n-1;i++)
        printf("%d ",sz[i]);
    return 0;
}

T2卡牌游戏

Description

小X 为了展示自己高超的游戏技巧,在某一天兴致勃勃地找小Y 玩起了一种卡牌游戏。每张卡牌有类型(攻击或防御)和力量值两个信息。

小Y 有n 张卡牌,小X 有m 张卡牌。已知小X 的卡牌全是攻击型的。

游戏的每一轮都由小X 进行操作,首先从自己手上选择一张没有使用过的卡牌X。如果小Y 手上没有卡牌,受到的伤害为X 的力量值,否则小X 要从小Y 的手上选择一张卡牌Y。若Y 是攻击型(当X 的力量值不小于Y 的力量值时才可选择),此轮结束后Y 消失,小Y 受到的伤害为X 的力量值与Y 的力量值的差;若Y 是防御型(当X 的力量值大于Y 的力量值时才可选择),此轮结束后Y 消失,小Y 不受到伤害。

小X 可以随时结束自己的操作(卡牌不一定要用完)。希望聪明的你帮助他进行操作,使得小Y 受到的总伤害最大。

Input

输入的第一行包含两个整数n 和m 。

接下来n 行每行包含一个字符串和一个整数,分别表示小Y 的一张卡牌的类型(“ATK”表示攻击型,“DEF”表示防御型)和力量值。

接下来m 行每行包含一个整数,表示小X 的一张卡牌的力量值。

Output

输出一行包含一个整数,表示小Y 受到的最大总伤害。
输入1:
2 3
ATK 2000
DEF 1700
2500
2500
2500

输入2:

3 4
ATK 10
ATK 100
ATK 1000
1
11
101
1001

Sample Output

输出1:
3000
【样例说明1】
第一轮,小X 选择自己的第一张卡牌和小Y 的第二张卡牌,小Y 的第二张卡牌消失。
第二轮,小X 选择自己的第二张卡牌和小Y 的第一张卡牌,小Y 的第一张卡牌消失,同时受到500 点伤害。
第三轮,小X 选择自己的第三张卡牌,此时小Y 手上已经没有卡牌,受到2500 点伤害。
小X 结束游戏,小Y 共受到3000点伤害。

输出2:
992
【样例说明2】
第一轮,小X 选择自己的第三张卡牌和小Y 的第一张卡牌,小Y 的第一张卡牌消失,同时受到91点伤害。
第二轮,小X 选择自己的第四张卡牌和小Y 的第二张卡牌,小Y 的第二张卡牌消失,同时受到901点伤害。
小X 结束游戏,小Y 共受到992点伤害。

Data Constraint

各规模均有一半数据满足小Y 只有攻击型卡牌。

对于30%的数据,1≤ n,m ≤ 6。

对于60%的数据,1≤ n,m ≤10^3。

对于100%的数据,1≤ n,m ≤10^5,力量值均为不超过10^6的非负整数。

考场思路/正解

贪心!考试时候就想到了,不过好像有两个小细节没处理好,结果考出来只有10分,emmmm。下午改题时,开了个long long 然后把一个语句从if中移了出来,就AC了,无语。。

在此题中,我们有两种打牌策略,一种是手上留情,不使对方的手牌全部消失,每次拿自己能力值最大的去和对手攻击手牌最小的去碰,直到自己手中最大的能力值小于对手的。

第二种打法是毫不留情,使对手的所有卡牌全部消失,然后用自己的攻击牌,狠狠打他的脸!但是要记得在消灭对手防御牌时要用自己手牌中能力值大于它且最小的牌,此处也是用贪心完成的,如果要优化,可以用二叉搜索树来查找,不过这里没有必要。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;

LL n,m,d,sl_d1,sl_d2,ans1,ans2,sl;
LL s1,s2;
LL def1[100010],def2[100010],atk[100010],book[100010];
char s[10],DEF[10]={'D','E','F'},ATK[10]={'A','T','K'};

LL Deal_def2_first()
{
    s1=1,s2=1,sl=0;
    while(s1<=m && s2<=sl_d2)
    {
        if(book[s1])
        {
            s1++;
            continue;
        }
        if(atk[s1]>=def2[s2])
        {
            ans1+=(atk[s1]-def2[s2]);
            book[s1]=1;
            s1++,s2++,sl++;
        }
        else
            s1++;
    }
    return sl<sl_d2 ? 0 : 1;
}

LL Deal_def1()
{
    s2=1,s1=1;
    while(s1<=m && s2<=sl_d1)
    {
        if(atk[s1]>def1[s2])
        {
            book[s1]=1;
            s1++,s2++,sl++;
        }
        else
            s1++;
    }
    return sl<sl_d1 ? 0 : 1;
}

void Deal_def2_second()
{
    s1=m,s2=1;
    while(s1>=1 && s2<=sl_d2)
    {
        if(atk[s1]>=def2[s2])
            ans2+=(atk[s1]-def2[s2]),s1--,s2++;
        else
            return;
    }
    
}

int main()
{
    scanf("%lld%lld",&n,&m);
    for(LL i=1;i<=n;i++)
    {
        scanf("%s %lld",s,&d);
        if(strcmp(s,DEF)==0)
            def1[++sl_d1]=d;
        if(strcmp(s,ATK)==0)
            def2[++sl_d2]=d;
    }
    for(LL i=1;i<=m;i++)
        scanf("%lld",&atk[i]);
    sort(atk+1,atk+1+m);
    sort(def1+1,def1+1+sl_d1);
    sort(def2+1,def2+1+sl_d2);
    if(Deal_def1())
        if(Deal_def2_first())
        for(LL i=1;i<=m;i++)
            if(!book[i])
                ans1+=atk[i];
    
    
    Deal_def2_second();
    printf("%lld",max(ans1,ans2));
    return 0;
}

T3舞台表演(原NOI2005瑰丽华尔兹)

Description

小X 终于找到了自己的舞台,希望进行一次尽兴的表演。

不妨认为舞台是一个n 行m 列的矩阵,矩阵中的某些方格上堆放了一些装饰物,其他的则是空地。小X 可以在空地上滑动,但不能撞上装饰物或滑出舞台,否则表演就失败了。

小Y 为了让小X 表演得尽量顺畅,提前为小X 写好了每一段时间的移动方向。每个时刻,听话的小X 都会依据小Y 写好的所在时间段的方向(东、西、南、北)向相邻的方格滑动一格。由于小Y 之前没有探查过舞台的情况,如果

小X 直接按照小Y 写好的来移动,很容易表演失败。

不过,小Y 是个天使,拥有让小X 停在原地的魔法,也就是某一时刻,小X 以为自己移动了实际上没有移动。为了让小X 表演得尽量完美,小Y 想使小X 在舞台上滑行的路程尽量长(当然不能中途表演失败)。可惜小Y 的智商不足

以完成这么复杂的计算,希望你来帮助她决定哪些时刻该使用魔法。当然,她关心的首先是最长的路程是多少。

Input

输入的第一行包含五个整数n,m, x, y 和k 。(x, y )为小 X的初始位置,k 为时间的段数。

接下来n 行每行包含m 个字符,描述这个舞台(“.”表示该位置是空地,“x”表示该位置有装饰物)。

接下来k 行每行包含三个整数si ti di (1<= i<= k ),表示在时间段[si,ti ] 内,小 X的移动方向是di 。di 为1,2,3,4中的一个,依次表示北、南、西、东(分别对应矩阵中的上、下、左、右)

Output

输出一行包含一个整数,表示小X 滑行的最长路程。
4 5 4 1 3
..xx.
.....
...x.
.....
1 3 4
4 5 1
6 7 3

Sample Output

6

Data Constraint

保证输入的时间段是连续的,即 s1 =1 ,si=ti-1+1(1<i<=k) ,tk=t。

对于30%的数据,1≤ t ≤ 20。

对于60%的数据,1≤t ≤ 200。

对于100%的数据,1≤ n,m,k ≤ 200,1≤t ≤10^5。

Hint

 

 

考场思路

好吧,我承认看到此题的时候我犯懒,然后就没有去打惹。

正解

DP+单调队列优化,但是,但是,但是我不会啊!!

Code

改天一定(看情况)补上代码!!
 
 

总结

发现自己在打题的时候不够认真,容易走神,注意力不集中,总是出现非智力因素的错误,and不爱打部分分等坏毛病。

希望日后能改正!!

 

距 NOIp2019 还剩 96 天        祭

 

 
 
posted @ 2019-08-04 21:19  Thm-V  阅读(108)  评论(0编辑  收藏  举报