D4题解

3403. 数列变换 (Standard IO)

Time Limits: 1000 ms  Memory Limits: 524288 KB

Goto ProblemSet

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。

思路

之前用两个数组模拟时间复杂度为O(n^{2})后来知道可以用两倍大的数组O(n*(r/n-l/n)因为r最大为2*n所以时间复杂度约为O(n*2)不知道他们怎么算出的O(n*log(n))

60分代码如下

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define LL long long
#define MAXN 1000005
int n,a[MAXN];
int d[MAXN];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)d[i]=i;
	for(int i=2;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			d[j]--;
			if(d[j]%i==0)d[j]=min(d[j]+i,n);
		}
	}
	for(int i=1;i<=n;i++)
		a[d[i]]=i;
	printf("%d",a[1]);
	for(int i=2;i<=n;i++)
		printf(" %d",a[i]);
}

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define LL long long
#define MAXN 1000005
int n,a[MAXN*2];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)a[i]=i;
	int l=1,r=n;
	for(int i=2;i<=n;i++)
	{
		int t=a[l];
		for(int j=l;j<=r;j+=i)
		{
			if(j+i>r)
			{
				a[++r]=t;
				l++;
				break;
			}
			swap(t,a[j+i]);
		}
	}
	for(int i=l;i<=r;i++)
		printf("%d ",a[i]);
}

3404. 卡牌游戏 (Standard IO)

Time Limits: 1000 ms  Memory Limits: 262144 KB  

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的非负整数。

思路

贪心,我打的比较复杂

代码

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
#define LL long long
#define MAXN 100005
int n,m,a;
LL x[MAXN],xx[MAXN];
char s[5];
vector<int>y1,y2;
LL ans,ans1;
bool cmp(int a,int b)
{
	return a>b;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%s%d",s,&a);
		if(s[0]=='A')
			y1.push_back(a);
		else
			y2.push_back(a);
	}
	for(int i=1;i<=m;i++)
		scanf("%d",&x[i]),xx[i]=x[i];
	if(n<m)
	{
		sort(xx+1,xx+m+1);
		if(y2.size()!=0)
		{
			sort(y2.begin(),y2.end());
			int k=upper_bound(xx+1,xx+m+1,y2[0])-xx;
			if(m-k+1>=y2.size())
			{
				int cnt=0;
				for(int i=k;i<=m&&cnt<y2.size();i++)
					if(xx[i]>y2[cnt])
						cnt++,xx[i]=0;
				if(cnt==y2.size())
				{
					sort(xx+1,xx+m+1,cmp);
					sort(y1.begin(),y1.end());
					int l=0,r=1;
					while(l<y1.size()&&xx[r]>y1[l])
						ans1+=xx[r]-y1[l],l++,r++;
					for(int i=r;i<=m&&xx[i]!=0;i++)
						ans1+=xx[i];
					printf("%lld",ans1);
					return 0;
				}
			}
		}
		else
		{
			sort(y1.begin(),y1.end());
			int k=lower_bound(xx+1,xx+m+1,y1[0])-xx;
			//printf("*%d",k);
			if(m-k+1>=y1.size())
			{
				int cnt=0;
				for(int i=k;i<=m&&cnt<y1.size();i++)
					if(xx[i]>y1[cnt])
						cnt++,xx[i]=0;
				if(cnt==y1.size())
				{
					for(int i=1;i<=m;i++)
						ans1+=x[i];
					for(int i=0;i<y1.size();i++)
						ans1-=y1[i];
					printf("%lld",ans1);
					return 0;
				}
			}
		}
	}
	sort(y1.begin(),y1.end());
	sort(x+1,x+m+1);
	int l=0,r=m;
	while(l<y1.size()&&r>0&&x[r]>y1[l])
		ans1+=x[r]-y1[l],l++,r--;
	printf("%lld",ans1);
}

3405. 舞台表演 (Standard IO)

Time Limits: 1000 ms  Memory Limits: 524288 KB 

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。

Hint

 思路

dp

状态定义:

f[k][x][y]:表示在k次停顿后到达(x,y)经过的最大路程

状态转移方程式:原地不动:f[i][x][y]=max(f[i][x][y],f[i-1][x][y]);

移动step步到(xa,ya)f[i][xa][ya]=max(f[i][xa][ya],f[i-1][xx][yy]+step);

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAXN 202
int n,m,k,ans;
char c[MAXN][MAXN];
struct node
{
	int s,t,d;
}a[MAXN];
int f[MAXN][MAXN][MAXN];
int dir[5][2]={{0,0},{-1,0},{1,0},{0,-1},{0,1}};
int x,y;
int main()
{
	memset(f,-1,sizeof(f));
	scanf("%d%d%d%d%d",&n,&m,&x,&y,&k);
	for(int i=1;i<=n;i++)
		scanf("%s",c[i]+1);
	for(int i=1;i<=k;i++)
		scanf("%d%d%d",&a[i].s,&a[i].t,&a[i].d);
	f[0][x][y]=0;
	for(int i=1;i<=k;i++)
		for(int xx=1;xx<=n;xx++)
			for(int yy=1;yy<=m;yy++)
				if(f[i-1][xx][yy]==-1)continue;
				else
				{
					
					f[i][xx][yy]=max(f[i][xx][yy],f[i-1][xx][yy]);//原地不动
					for(int step=1;step<=a[i].t-a[i].s+1;step++)
					{
						int xa=xx+step*dir[a[i].d][0],ya=yy+step*dir[a[i].d][1];
						//printf("%d %d %d %d\n",xa,ya,xx,yy);
						if(c[xa][ya]=='x'||xa<=0||xa>n||ya<=0||ya>m)break;
						f[i][xa][ya]=max(f[i][xa][ya],f[i-1][xx][yy]+step);
						if(f[i][xa][ya]>ans)ans=f[i][xa][ya];
						//printf("%d\n",ans);
					}
				}
	printf("%d",ans);
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值