题解 - Codeforces Round #637 (Div. 2,A-E)

C o d e f o r c e s   R o u n d   637   ( D i v . 2   A E ) \mathrm{Codeforces\ Round \ 637 \ (Div. 2\ A-E) }

A . N a s t y a   a n d   R i c e \mathrm{A.Nastya\ and \ Rice }

难度: 1000 *1000

题目描述 :传送门

S o l \mathrm{Sol}

  • 简单题,因为 a i [ a b , a + b ] , a i [ c d , c + d ] a_i∈[a-b,a+b],\sum a_i∈[c-d,c+d] 。那么我们只要判断对于每个 a i a_i 最差以及最好的情况与 [ c d , c + d ] [c-d,c+d] 进行比较即可。

C o d e \mathrm{Code}

#include <bits/stdc++.h>
using namespace std;

inline int read()
{
	int sum=0,ff=1; char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') ff=-1;
		ch=getchar();
	}
	while(isdigit(ch))
		sum=sum*10+(ch^48),ch=getchar();
	return sum*ff;
}

int n,m,x,y,a,b;

int main()
{
	int Q=read();
	for (;Q--;)
	{
		n=read();
		x=read();
		y=read();
		a=read();
		b=read();
		int low=x-y,high=x+y;
		if(low*n<=a+b&&high*n>=a-b) puts("Yes");
		else puts("No");
	}
	return 0;
}
		 

B . N a s t y a   a n d   D o o r \mathrm{B.Nastya\ and \ Door }

难度: 1300 *1300

题目描述 :传送门

S o l \mathrm{Sol}

  • 模拟题,我们统计一个 P e a k s   o f   m o u n t a i n s \mathrm{Peaks\ of \ mountains} 的数量的前缀和,然后去枚举每一个长度为 k k 的合法的开区间,然后用前缀和查询,最后再枚举一便找到一个解就可以,并且最后不要忘记加 1 1

C o d e \mathrm{Code}

#include <bits/stdc++.h>
#define pb push_back
using namespace std;

inline int read()
{
	int sum=0,ff=1; char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') ff=-1;
		ch=getchar();
	}
	while(isdigit(ch))
		sum=sum*10+(ch^48),ch=getchar();
	return sum*ff;
}

const int N=2e5+5;

int T,n,k,s[N],a[N];

int main()
{
	T=read();
	while(T--)
	{
		n=read(),k=read();
		a[0]=a[n+1]=1e9+5;
		for ( int i=1;i<=n;++i )
			a[i]=read();
		for ( int i=1;i<=n;++i) 
		{ 
			s[i]=s[i-1];
			if(a[i]>a[i-1]&&a[i]>a[i+1])
				s[i]++;
		}
		int pos=0,ans=0;
		for ( int i=k;i<=n;++i )
			if(ans<s[i-1]-s[i-k+1]+1)
			{
				pos=i-k+1;
				ans=s[i-1]-s[i-k+1]+1;
			}
		printf("%d %d\n",ans,pos);
	}
	return 0;
}

C . N a s t y a   a n d   S t r a n g e   G e n e r a t o r \mathrm{C.Nastya\ and \ Strange \ Generator }

难度: 1500 *1500

题目描述 :传送门

S o l \mathrm{Sol}

  • 结论题:如果序列 p p 可以分为多个小段,那么每个小段都是以 1 1 为公差的递增等差数列,则可以成功构造。具体证明就不写了(qwq

C o d e \mathrm{Code}

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;

inline int read()
{
	int sum=0,ff=1; char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') ff=-1;
		ch=getchar();
	}
	while(isdigit(ch))
		sum=sum*10+(ch^48),ch=getchar();
	return sum*ff;
}

int a[N];

signed main()
{
	int Q=read();
	for (;Q--;)
	{
		int n=read();
		int flg=0;
		for ( int i=1;i<=n;i++ ) a[i]=read();
		for ( int i=1;i<=n;i++ )
		{
			int j=i;
			while(j+1<=n&&a[j+1]>a[j])  j++ ;
			for ( int k=i;k<j;k++ ) 
				if((a[k]+1)^a[k+1])  
					flg=1;
			i=j;
		}
		if(flg) puts("No");
		else puts("Yes");
	}
	return 0;
}

D . N a s t y a   a n d   S c o r e b o a r d \mathrm{D.Nastya\ and \ Scoreboard }

难度: 1800 *1800

题目描述 :传送门

S o l \mathrm{Sol}

  • 比较基础的 D P DP 以及贪心

  • 我们首先设 f i , j f_{i,j} 为到第 i i 块用了 j j 个额外木棒是否能够构成数字。转移就很简单: f i , j = [ k = 0 9 ] f i 1 , j c i , k f_{i,j}|=[_{k=0}^{9}]f_{i-1,j-c_{i,k}} c i , j c_{i,j} 是:第 i i 块变成数字 j j 的需要木棒数(如果无法变,那么 c i , j = i n f c_{i,j}=inf ),可以预处理得到。

  • 然后我们再用 g i , j g_{i,j} 到第 i i 块用 j j 根木棒需要变成的数字,转移时修改即可。

  • 我们还有一个贪心策略,就是从高位做到低位即可。

C o d e \mathrm{Code}

#include <bits/stdc++.h>
#define pb push_back
using namespace std;

inline int read()
{
	int sum=0,ff=1; char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') ff=-1;
		ch=getchar();
	}
	while(isdigit(ch))
		sum=sum*10+(ch^48),ch=getchar();
	return sum*ff;
}

const int N=2e3+5;

string s[11]=
	{"1110111","0010010","1011101","1011011","0111010","1101011","1101111","1010010","1111111","1111011"};
int n,m,f[N][N],g[N][N],c[N][11],h[N];
string a[N];

inline int calc(int x,int y)
{
	int gs=0;
	for ( int i=0;i<7;i++ ) 
	{
		if(a[x][i]=='1'&&s[y][i]=='0') return 1e9;
		else 
			if(a[x][i]=='0'&&s[y][i]=='1') gs++;
	}
	return gs;
}

int main()
{
	n=read();
	m=read();
	memset(f,-1,sizeof(f));
	int alb=0;
	for ( int i=1;i<=n;i++ ) 
	{
		cin>>a[i];
		for ( int j=0;j<=9;j++ ) 
		{
			int flg=1;
			for ( int k=0;j<7;k++ ) 
				if(a[i][k]!=s[j][k]) 
				{
					flg=0;
					break;
				}
			alb|=flg;
		}
	}
	if(!alb) return puts("-1"),0;
	reverse(a+1,a+n+1);
	for ( int i=1;i<=n;i++ ) 
	{
		for ( int j=0;j<=9;j++ ) 
			c[i][j]=calc(i,j);
		int flg=1;
		for ( int j=0;j<=9;j++ ) 
			if(c[i][j]!=1e9) flg=0;
		if(flg) return puts("-1"),0;
	}
//	for ( int i=1;i<=n;i++,puts("") ) 
//		for ( int j=0;j<=9;j++ ) 
//			printf("c[%d][%d]=%d\n",i,j,c[i][j]);
	f[0][0]=1;
	for ( int i=1;i<=n;i++ ) 
		for ( int j=0;j<=m;j++ ) 
			for ( int k=0;k<=9;k++ ) 
			{
				int cost=c[i][k];
				if(j-cost<0||cost==1e9) continue;
				if(~f[i-1][j-cost])
					f[i][j]=1,g[i][j]=k;
			}
	if(!(~f[n][m])) return puts("-1"),0; 
	for ( int i=n;i>=1;i-- ) 
	{
		int x=g[i][m];
//		printf("x=%d c[%d][%d]=%d\n",x,i,x,c[i][x]); 
		printf("%d",x);
		m-=c[i][x];
	}
	return 0;
}

E . N a s t y a   a n d   U n e x p e c t e d   G u e s t \mathrm{E.Nastya\ and \ Unexpected \ Guest }

难度: 2300 *2300

题目描述 :传送门

S o l \mathrm{Sol}

  • 首先我们来感谢素质出题人没对 d i d_i 排序

  • 我们回到这题:我们先设 f i , j f_{i,j} 表示到 d i d_i ,以及对于不完整的一个周期 ( g + r ) (g+r) 多出 j j 秒的最小周期数(因为周期与周期之间本质相同的)。

  • 然后对于每一个关键点分类讨论(即向左,向右)这边我们具体来讲一下向左。假设此时为 d i d_i ,那么左边即为 d i 1 d_{i-1} (注意边界),以及不往左走前已经多出来 j j 秒。

    • 如果 ( d i d i 1 + j ) < g (d_i-d_{i-1}+j)<g ,那么 f i 1 , ( d i d i 1 + j ) = f i , j f_{i-1,(d_i-d_{i-1}+j)}=f_{i,j}

    • 如果 ( d i d i 1 + j ) = g (d_i-d_{i-1}+j)=g ,那么 f i 1 , 0 = f i , j + 1 f_{i-1,0}=f_{i,j}+1 。应为一个周期满了,需要重开一个(很显然)

  • 到这里我们发现边权只存在 0 , 1 0,1 ,那么我们只需要 01 b f s 01bfs 即可。具体的就是搞个双端队列,对于边权为 1 1 p u s h b a c k pushback 否者 p u s h f r o n t pushfront

C o d e \mathrm{Code}

#include <bits/stdc++.h>
#define pb push_back
#define int long long
using namespace std;

inline int read()
{
	int sum=0,ff=1; char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') ff=-1;
		ch=getchar();
	}
	while(isdigit(ch))
		sum=sum*10+(ch^48),ch=getchar();
	return sum*ff;
}

const int N=1e6+5;
const int M=1e4+5;

int n,m,d[M],R,G,dis[M][1005],ans;
deque<pair<int,int> >q;

signed main()
{
	n=read();
	m=read();
	for ( int i=1;i<=m;i++ ) d[i]=read();
	G=read();
	R=read();
	sort(d+1,d+m+1);
	memset(dis,-1,sizeof(dis));
	q.push_front(make_pair(1,0));
	dis[1][0]=0;
	while(!q.empty())
	{
		pair<int,int> v=q.front();
		q.pop_front();
		if(v.first>1) 
		{
			int del=d[v.first]-d[v.first-1]+v.second;
			if(del<G) 
			{
				if(dis[v.first-1][del]<0)
				{
					dis[v.first-1][del]=dis[v.first][v.second];
					q.push_front(make_pair(v.first-1,del));
				}
			}
			if(del==G)
			{
				if(dis[v.first-1][0]<0)
				{
					dis[v.first-1][0]=dis[v.first][v.second]+1;
					q.push_back(make_pair(v.first-1,0));
				}
			}
		}
		if(v.first<m)
		{
			int del=d[v.first+1]-d[v.first]+v.second;
			if(del<G)
			{
				if(dis[v.first+1][del]<0)
				{
					dis[v.first+1][del]=dis[v.first][v.second];
					q.push_front(make_pair(v.first+1,del));
				}
			}
			if(del==G)
			{
				if(dis[v.first+1][0]<0)
				{
					dis[v.first+1][0]=dis[v.first][v.second]+1;
					q.push_back(make_pair(v.first+1,0));
				}
			}
		}
	}
	int ans=-1;
	for ( int i=0;i<G;i++ ) 
	{
		if(dis[m][i]<0) continue;
		int gs=dis[m][i];
		int tim=1ll*gs*(R+G)+i;
		if(!i&&dis[m][i]) tim-=R;
		if(ans<0||ans>tim) ans=tim;
	}
	printf("%lld\n",ans);
	return 0;
}
	

猜你喜欢

转载自blog.csdn.net/wangyiyang2/article/details/105889409