【纪中受难记】——Day4:失去梦想的咸鱼

世界上没有什么困难能阻挡我前进,除非是调试一个水题调了半个小时……

0/40(60?)/0


 

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。

这道题在听到一位神仙说出解法前,还以为正解是dp……

解法就是将数组不断右移,然后把跳到尾端的移到下一个即将跳到尾端的数字上去。

eg:1 2 3 4 

k=2:1  2  1 4 3

k=3:1  2 1 4 2  3

注意到最后一个区间跳跃的数,它应该预判一下n%k是否等于0,如果整除就不用管(我被坑了好久)。

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int N=1e6+10;
 5 int n;
 6 int b[N*2];
 7 int main(){
 8     scanf("%d",&n);
 9     for(int i=1;i<=n;i++){
10         b[i]=i;
11     } 
12     for(int k=2;k<=n;k++){
13         int tail=n-n%k+k-1,re=b[tail];
14         for(int i=tail;i>=k-1;i-=k){
15             b[i]=b[i-k];
16         }
17         if(n%k!=0)
18         b[n+k-1]=re;
19     }
20     for(int i=n;i<=2*n-1;i++)
21     printf("%d ",b[i]);
22     return 0;
23 }

 

3404. 卡牌游戏 (Standard IO)

Time Limits:  1000 ms  Memory Limits: 524288 KB  Detailed Limits  
Goto ProblemSet
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 受到的最大总伤害。
 
Sample Input
输入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的非负整数。

这道题是贪心。

考虑几种情况:

1.只消耗对方攻击牌:

  我们用最大的攻击牌攻击对方最小的攻击牌,然后拿次大的攻击次小的,证明如下:

  如果存在一个牌x<对方某一攻击牌y,我方共用牌点为X,对方为Y,则我方得分为X-Y,但是可知x-y<0 所以再攻击也不会得到更多优势,故不去攻击。

2.消耗对方所有牌再造成直接伤害:

    如果消耗所有牌的话,应当先攻击防御牌,用等大或者稍大的牌消掉防御牌再去攻击其他的,假设能消耗所有攻击牌,则得分为:sum[x]-def[x]-atk[y](sum是我方牌总分数,def是用在攻击防御牌上的总分数,atk是敌方攻击牌总分数)

以上两种情况取最大即可。

不知道为啥只有80分。

 

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef long long ll;
 7 const ll N=1e5+10;
 8 ll n,m,ans,maxans;
 9 ll atk[N],dfn[N],ca,cb,vis[N],flag1,flag2;
10 ll x[N];
11 int main(){
12     freopen("card17.in","r",stdin);
13     scanf("%lld%lld",&n,&m);
14     char a[10];
15     ca=cb=0;
16     for(ll i=1,k;i<=n;i++){
17         cin>>a;
18         scanf("%lld",&k);
19         if(a[0]=='A') atk[++ca]=k;
20         else dfn[++cb]=k;
21     }    
22     sort(atk+1,atk+ca+1);
23     sort(dfn+1,dfn+cb+1);
24     for(ll i=1;i<=m;i++) scanf("%lld",&x[i]);
25     sort(x+1,x+m+1);
26     ll ans=0;
27     ll i,j;
28     for(i=1,j=1;i<=ca&&j<=m;){
29         while((x[j]<atk[i]&&j<=m)||vis[j]) j++;
30         if(j>m) break;
31         ans+=x[j]-atk[i];
32         vis[j]=1;
33         i++;
34     }
35     if(i>ca) flag1=1;
36     for(i=1,j=1;i<=cb&&j<=m;){
37         while((x[j]<dfn[i]&&j<=m)||vis[j]) j++;
38         if(j>m) break;
39         vis[j]=1,i++;
40     }
41     if(i>cb) flag2=1;
42     if(flag1&flag2) for(i=1;i<=m;i++) if(!vis[i]) ans+=x[i];
43     maxans=max(ans,maxans);
44     memset(vis,0,sizeof(vis));
45     flag1=flag2=ans=0;
46     for(i=1,j=1;i<=cb&&j<=m;){
47         while((x[j]<dfn[i]&&j<=m)||vis[j]) j++;
48         if(j>m) break;
49         vis[j]=1,i++;
50     }
51     if(i>cb) flag2=1;
52     for(i=1,j=1;i<=ca&&j<=m;){
53         while((x[j]<atk[i]&&j<=m)||vis[j]) j++;
54         if(j>m) break;
55         ans+=x[j]-atk[i];
56         vis[j]=1;
57         i++;
58     }
59     if(i>ca) flag1=1;
60     if(flag1&flag2) for(i=1;i<=m;i++) if(!vis[i]) ans+=x[i];
61     maxans=max(maxans,ans);
62     memset(vis,0,sizeof(vis));
63     flag1=flag2=ans=0;
64     ll pt[N];
65     for(ll i=m,j=1;i>=1&&j<=ca;){
66         if(x[i]>atk[j]) ans+=x[i]-atk[j],vis[i]=1,i--,j++;
67         else break;
68     }
69     ll t=0;
70     for(ll i=1;i<=m;i++) if(vis[i]) t++; 
71     if(t==ca) flag1=1;
72     for(i=1,j=1;i<=cb&&j<=m;){
73         while((x[j]<dfn[i]&&j<=m)||vis[j]) j++;
74         if(j>m) break;
75         vis[j]=1,i++;
76     }
77     if(i>cb) flag2=1;
78     if(flag1&flag2) for(i=1;i<=m;i++) if(!vis[i]) ans+=x[i];
79     maxans=max(maxans,ans);
80     printf("%lld",maxans);
81     return 0;
82 }

 


3405. 舞台表演 (Standard IO)

Time Limits:  1000 ms  Memory Limits: 524288 KB  Detailed Limits  
Goto ProblemSet
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 滑行的最长路程。
 
Sample Input
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。

这题调试要了我老命。

读题目,这道题并不难设状态,设f[k][i][j]表示在第k次转弯后停在(i,j)时走的最长步数,

f[k][i][j]=max(f[k-1][x][y]+step),其中(x,y)表示上次停的位置,枚举这个位置,然后更新方向上的step就可以了。

注意一点,初始状态除了起点以外都为-1。

 

 1 #include<bits/stdc++.h>
 2 #pragma GCC optimize(3) 
 3 using namespace std;
 4 const int N=210;
 5 const int T=1e5+10;
 6 int n,m,xx,yy,k;
 7 int a[N][N];
 8 int f[N][N][N],ans;
 9 struct Time{
10     int s,t,d;
11 }r[N];
12 int main(){
13     scanf("%d%d%d%d%d",&n,&m,&xx,&yy,&k);
14     char q;
15     for(int i=1;i<=n;i++){
16         for(int j=1;j<=m;j++){
17             cin>>q;
18             a[i][j]=(q=='.'?0:1);
19         }
20     }
21     int s,t,d;
22     int maxt=0;
23     for(int i=1;i<=k;i++){
24         scanf("%d%d%d",&s,&t,&d);
25         r[i]=(Time){s,t,d};
26     }
27     memset(f,-1,sizeof(f));
28     f[0][xx][yy]=0;
29     for(int i=1;i<=k;i++){
30         for(int x=1;x<=n;x++){
31             for(int y=1;y<=m;y++){
32                 if(f[i-1][x][y]==-1) continue;
33                 f[i][x][y]=max(f[i][x][y],f[i-1][x][y]);
34                 if(r[i].d==1){
35                     for(int step=1;step<=r[i].t-r[i].s+1;step++){
36                         if(a[x-step][y]||x-step<=0) break;
37                         f[i][x-step][y]=max(f[i][x-step][y],f[i-1][x][y]+step);
38                         if(f[i][x-step][y]>ans) ans=f[i][x-step][y];
39                     }
40                 }
41                 else if(r[i].d==2){
42                     for(int step=1;step<=r[i].t-r[i].s+1;step++){
43                         if(a[x+step][y]||x+step>n) break;
44                         f[i][x+step][y]=max(f[i][x+step][y],f[i-1][x][y]+step);
45                         if(f[i][x+step][y]>ans) ans=f[i][x+step][y];
46                     }
47                 }
48                 else if(r[i].d==3){
49                     for(int step=1;step<=r[i].t-r[i].s+1;step++){
50                         if(a[x][y-step]||y-step<=0) break;
51                         f[i][x][y-step]=max(f[i][x][y-step],f[i-1][x][y]+step);
52                         if(f[i][x][y-step]>ans) ans=f[i][x][y-step];
53                     }
54                 }
55                 else{
56                     for(int step=1;step<=r[i].t-r[i].s+1;step++){
57                         if(a[x][y+step]||y+step>m) break;
58                         f[i][x][y+step]=max(f[i][x][y+step],f[i-1][x][y]+step);
59                         if(f[i][x][y+step]>ans) ans=f[i][x][y+step];
60                     }
61                 }
62             }
63         }
64     }
65     printf("%d",ans);
66     return 0;
67 }

 


 

总结:下次要比今天多100分,否则就太菜了。

 

转载于:https://www.cnblogs.com/Nelson992770019/p/11299327.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值