2020牛客暑期多校训练营(第三场)题解

A :Clam and Fish
简要题意 •
小月有 n 单位的时间都在钓鱼,每个单位时间有四种状态,
。蛤蜊 鱼
0:0 // 0
1:0 //1
2:1//0
3: 1//1
小月事先知道这 n 个时间点的状态。每个时间点有四种可能 的动作:

  1. 若该时间点有鱼,则可以直接钓鱼。
  2. 若该时间点有蛤蜊,则可以用该蛤蛎制作一个鱼饵。
  3. 若该时间点身上有至少一个鱼饵,则可以用一个鱼饵钓一条鱼,钓完后就少 了一个鱼饵。
  4. 什么事都不做。
    请问小月最多可以钓多少条鱼。
    输入
    2
    4
    0103
    1
    1
    输出
    2
    0
    备注:
    One possible scenario you can catch two fishes is as follow:
    stage 1: Do nothing.
    stage 2: Make a pack of fish bait.
    stage 3: Catch a fish by a pack of fish bait.
    stage 4: Catch the fish that appears in the stage.

状态2,3 有鱼直接钓鱼,状态1,0顺序配合钓鱼,状态1,1顺序配合钓鱼

#include
using namespace std;
#define ll long long
string s;
int yi;
int main()
{
 ios::sync_with_stdio(false);
 int t,n,m,yu=0;
 cin>>t;
 while(t--)
 {
 	yu=0;yi=0;
 	cin>>n;
 	cin>>s;
 	for(int i=0;i

B:Classical String Problem
简要题意:
有一个字符串,有两种操作:

  1. 询问第 x 个字符。
  2. 把最左边的 x 个字符搬到最右边或把最右边 x 个字符搬到最左边。
    官方题解:
    想像成字符串是头尾接在一起的 ,只需维护一个指针指向当前第一个字符 的位置,就能以 O(1) 的时间复杂度进行每个操作。
    • 以 Sample 为例 •
    初始时指针在 n 的前面 |nowcoder •
    操作 1 询问指针右边第 1 个字符,答案是 n •
    操作 2 把 4 个字符搬到右边,相当于把指针向右移 4 个字符 nowc|oder •
    操作 3 询问指针右边第 6 个字符,答案是 o •
    操作 4 把右边 3 个字符搬到右边,相当于把指针向左移 3 个字符 n|owcoder •

输入
nowcoder
6
A 1
M 4
A 6
M -3
M 1
A 1
输出
n
o
w

#include
using namespace std;
#define ll long long
int main()
{
 ios::sync_with_stdio(false);
 int n,tmp,tip=0,len;
 string s;
 char c;
 cin>>s>>n;
 len=s.length();
 while(n--)
 {
 	cin>>c>>tmp;
 	if(c=='A') cout<0) tip=(tip+tmp)%len;
      else tip=(tip+tmp+len)%len;      
	}
 }
 return 0;	
} 

C:Operation Love
图为某机器人右手手印的形状,左手为右手的对称图形,现在给你一个机器人 手印(可能经过平移及旋转,大小不变),请判断是左手还右手(保证一定是其中一只手) 。
2020牛客暑期多校训练营(第三场)题解_第1张图片
找出边长为6和9的两条边,判断顺逆,注意精度

#include
using namespace std;
#define ll long long
double x[25],y[25];
const double eps=0.1; //偏差值,有时用1e-10 
int sgn(double x)//判断x是否等于0 
{
 if(fabs(x)>t;
 while(t--)
 {
 	for(int i=0;i<20;i++)
 	 cin>>a[i].x>>a[i].y;
 	int bo;
 	for(int i=0;i<20;i++)
 	{
 	 if(sgn(dis(a[i],a[(i+19)%20])-36)==0&&sgn(dis(a[i],a[(i+1)%20])-81)==0)  
 	 {
 	  bo=sgn(cross(a[(i+19)%20]-a[i],a[(i+1)%20]-a[i]));
	  break;	
	 }
 	 if(sgn(dis(a[i],a[(i+19)%20])-81)==0&&sgn(dis(a[i],a[(i+1)%20])-36)==0) 
 	 {
 	  bo=sgn(cross(a[(i+1)%20]-a[i],a[(i+19)%20]-a[i]));
	  break;	
	 } 	 
	}
 	if(bo==-1) cout<<"right"<

D:Points Construction Problem
在无限大的格子盘面中,原本所有格子都是白色的,请把其中 n 个格 子涂黑,使得满足格子 x 和格子y 是上下左右相邻且 x , y 异色的 (x,y) 组数恰好为k 个((x,y)和(y,x) 视为相同)。

#include
using namespace std;
#define ll long long
int main() 
{
    ios::sync_with_stdio(false);
	int t,n,m,x,y,sum,tmp,res; 
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        if(m%2||m>4*n||m*m<16*n)//m为偶数,最大值4n,最小值m^2>=16n 
         cout<<"No"<<endl;
        else
        {
        	cout<<"Yes"<<endl;
        	int sum=2*n+2;//当n为一排过去时的边数
        	if(m>sum) //两种情况,一些在一排里,一些落单 
        	{
        		tmp=(m-sum)/2;// 
        		for(int i=1;i<=n-tmp;i++) //一排过去,每次边+2 
        		 cout<<1<<" "<<i<<endl;
        		for(int i=3;i<=3+tmp-1;i++) //斜线,每次边+4 
        		 cout<<i<<" "<<i<<endl;
			}
			else//L型,最佳情况,abs(x-y)<=1
			{
				//m=2(x+y),极值在abs(x-y)<=1处取到,所以x=m/4 
				x=m/4;y=m/2-x; // 
				for(int i=1;i<=x;i++)
				 cout<<i<<" "<<1<<endl;
				for(int i=2;i<=y;i++)
				 cout<<1<<" "<<i<<endl;
				//L型,往里填方格,边不变 
				res=n-(x+y-1);//已填x+y-1个 
				for(int i=2;i<=x&&res;i++)
				 for(int j=2;j<=y&&res;j++,res--)
				  cout<<i<<" "<<j<<endl;
			}
		}
    }
    return 0;
}

E:Two Matchings
详解
dp[i]=min(dp[i-4]+dp[i]-dp[i-3],dp[i-6]+dp[i]-dp[i-5]);

#include
using namespace std;
#define ll long long
ll dp[200100]; 
int main()
{
 ios::sync_with_stdio(false);
 int t,n;
 cin>>t;
 while(t--)
 {
 	cin>>n;
 	for(int i=1;i<=n;i++)
 	 cin>>dp[i];
 	sort(dp+1,dp+n+1);
 	dp[4]-=dp[1];
 	dp[6]-=dp[1];
 	dp[8]=dp[8]-dp[5]+dp[4];
 	for(int i=10;i<=n;i+=2)
 	 dp[i]=min(dp[i-4]+dp[i]-dp[i-3],dp[i-6]+dp[i]-dp[i-5]);
 	cout<<2*dp[n]<

F: Fraction Construction Problem
详解

#include
using namespace std;
#define ll long long
ll gcd(ll a,ll b) 
{
    return b==0? a:gcd(b,a%b);
}
void exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b)
    {
        x=1;y=0;return;
    }
    exgcd(b,a%b,y,x);
    y-=a/b*x;
}
int pri[2000100],cnt=0;
bool st[2000100];
int m[2000100];//数字i的最小因子(除了1)
void prime()
{
 m[0]=m[1]=1;
 for(int i=2;i<=2000000;i++)
  if(m[i]==0)
  {
   for(int j=i;j<=2000000;j+=i)
    if(m[j]==0)
    m[j]=i;
  }
}
int main()
{
 ios::sync_with_stdio(false);
 int t,a,b,g;
 cin>>t;
 prime();
 while(t--)
 {
   cin>>a>>b;
   g=gcd(a,b); 
   if(g>1)
    cout<

G:Operating on a Graph
官方题解:
给一个 n 个点的 Graph,第 i 个点一刚开始是第 I 种颜色,接着有 k 次 操作,第 i 次操作有个参数 oi 代表颜色 oi 会侵略所有和自己相邻的颜色, 于是所有和 oi 相邻的颜色全都变成 oi (若已没有颜色oi 已被侵略,则该次操作无效),求最终每个点的颜色。

  1. 对于每个颜色都维护一个点的链表,储存该颜色中尚未把所有相邻点变为自己颜色的点。
  2. 用并查集纪录每个点属于哪个颜色。
  3. 每次操作就会把颜色 oi 的链表中所有相邻的点所属的颜色都变为 oi , 就直接把对应的链表合并以及在并查集上做对应的操作、
#include
using namespace std;
#define ll long long
listG[800100];
int t,n,m,u,v,q,num,fa[800100],fx,fy;
int find(int x)     //找到并更新最终结点
{
    if(x!=fa[x])
     x=fa[x]=find(fa[x]);
    return x;
}
void merge(int x,int y) // 
{
    fx=find(x);
    fy=find(y);
    if(fx==fy) return; //本来就在一组,不用修改 
    fa[fy]=fx;  
    G[fx].splice(G[fx].end(),G[fy]);// 合并 
    G[fy].clear();  //删去
}
int main() 
{
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        for(int i=0;i>q;
        while(q--)
        {
            cin>>num;
            if(find(num)!=num)
                continue;
            //把相连的点归到自己一组 
            vectorv;
            for(auto &j: G[num])  //相连的点 
            {
                if(find(j)!=num)  //需要修改的点 
                 v.push_back(j);
            }
            G[num].clear(); //清空 
            for(auto &j:v)    //修改 
            {
                merge(num,j);
            }
        }
        for (int i=0;i

L:Problem L is the Only Lovely Problem
判断一个字符串是否为 lovely 开头,不分大小写。

#include
using namespace std;
#define ll long long
int main()
{
 ios::sync_with_stdio(false);
 string s;
 cin>>s;
 for(int i=0;i<6;i++)
  if(s[i]>='A'&&s[i]<='Z')
   s[i]=s[i]-'A'+'a';
 if(s.length()>=6&&s.substr(0,6)=="lovely") cout<<"lovely"<

你可能感兴趣的:(2020牛客暑期多校训练营(第三场)题解)