黑龙江2019校赛 题解报告

这套题是和队友一起做的,我就把我会写的讲一下吧。

a.很简单,观察一下就发现是个123456789的等差数列,运用求和公式求出在哪个区间,然后在判断第几个就好了

#include<bits/stdc++.h>
using namespace std;
int main()
{
    long long n;
    scanf("%lld",&n);
    while(n--)
    {
    long long x;
       scanf("%dll",&x);
       long long cnt=1;
       while(cnt*(cnt+1)/2<x)cnt++;
       cnt--;
       long long x1=x-1ll*cnt*(cnt+1)/2;
       x1%=26;
       if(x1==0)x1=26;
       printf("%c\n",x1+'a'-1); 
    }

b题.把公式拆分出来发现是个系数为n-1的平方和减去2*混合积,求混合积的时候提取因子就出来了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+10;
#define ll long long
#define up(i,a,n) for(int i=a;i<=n;i++)
int arr[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        int m;
        ll sum=0;
        ll s=0;
        scanf("%d",&m);
        up(i,1,m)
        {
            scanf("%d",&arr[i]);
            sum+=arr[i];
            s+=(1ll*(m-1)*arr[i]*arr[i]);
        }
        up(i,1,m-1)
        {
            sum-=arr[i];
            s-=2*sum*arr[i];
        }
        printf("%lld\n",s);
    }
}

C题,题目很简单,至于原因。因为连续两个相邻的数必然互质,只要顺序成环就好

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        int x;
        scanf("%d",&x);
        printf("%d\n",x);
    }
}

H 题,要去求出每个单词最晚背的天数,两个数组,维护行和列,然后取最大就好了

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define up(i,a,n) for(int i=a;i<=n;i++)
const int maxn=1e5+10;
int h[maxn];
int l[maxn];
int main()
{
    int n,m,t;
    scanf("%d %d %d",&n,&m,&t);
    for(int i=1;i<=t;i++)
    {
        int x,y;
        scanf("%d %d",&x,&y);
        if(x==1)h[y]=i;
        else l[y]=i;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            printf("%d ",max(h[i],l[j]));
        }
        printf("\n");
    }
}

G 题 

博弈论入门:

解释一下样例吧

如果n=20,m=6;那么谁喊价到19谁赢,那么可以从[13,18]喊到19,那么[13,18]为必败区间,12则为必胜,类推下去,[6,11]为必败,

5为必胜,然后Alice只要一上来叫6,那就稳赢了。

如果n=10,m=2;那么谁先到9谁赢,然后类推[7,8]败,6赢,[4,5]败3赢,[1,2]败,那Alice不管选,1,2都是败,观察到;

每个周期开始时为n-1,周期长度为m+1,那么只要考虑n-1能不能整除m+1就好了(这个游戏先手优势太大了吧)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        int P,M;
        scanf("%d %d",&P,&M);
        P--;
        M++;
        if(P%M==0)printf("Bob\n");
        else printf("Alice\n");
 
    }
}

F 题,是一道线段树的题,不过值得学习的是,这个线段树需要剪枝,这就是比较难想到的地方了,不得不说感觉这题挺好的。

首先考虑树上需要有啥,gcd,以及sum,sum是用来判断是否全1用的。

怎么更新gcd? 很简单,因为gcd具有合并性(可能这里表达不太准确),也就是gcd(a,b,c)=gcd(gcd(a,b),c);叶节点就直接等于原数。其他的就如同普通线段树一般就ok了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
#define fin(a,n) for(int i=a;i<=n;i++)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define llson l,r,rt<<1
#define rrson l,r,rt<<1|1
#define inf 1<<29
#define ll long long 
#define gcd(a,b) __gcd(a,b)
const int maxn=2e5+10;
int flag=0;
struct node
{
	int l,r,sum;
	ll g;
}tree[maxn<<2];
void PushUp(int rt)
{   
    tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
	tree[rt].g=gcd(tree[rt<<1].g,tree[rt<<1|1].g);
}
void build(int l,int r,int rt)
{   tree[rt].l=l;
    tree[rt].r=r;
    tree[rt].sum=0;
	if(l==r)
	{   
	    scanf("%lld",&tree[rt].g);
	    if(tree[rt].g==1)tree[rt].sum=1;
	    return ;
	}
	int m=(tree[rt].l+tree[rt].r)>>1;
	build(lson);
	build(rson);
	PushUp(rt);
}
void Update(int L,int R,int rt)
{   
    //if(tree[rt].g==1)return ;
    if(tree[rt].sum==tree[rt].r-tree[rt].l+1)return ;
	if(tree[rt].l==tree[rt].r)
	{
		tree[rt].g=(ll)sqrt(tree[rt].g);
		if(tree[rt].g==1)tree[rt].sum=1;
		return ;
	}
	int m=(tree[rt].l+tree[rt].r)>>1;
	if(L<=m)Update(L,R,rt<<1);
	if(R>m)Update(L,R,rt<<1|1);
	PushUp(rt);
}
ll Query(int L,int R,int rt)
{   
	if(flag)return 1;
	if(L<=tree[rt].l&&R>=tree[rt].r)
	{   if(tree[rt].g==1)flag=1;
		return tree[rt].g;
	}
	ll ans=0;
	int m=(tree[rt].l+tree[rt].r)>>1;
	if(L<=m)ans=gcd(Query(L,R,rt<<1),ans);
	if(R>m)ans=gcd(ans,Query(L,R,rt<<1|1));
	return ans;
}
int main()
{
	int n;
	scanf("%d",&n);
	build(1,n,1);
	int m;
	scanf("%d",&m);
	while(m--)
	{   flag=0;
		int op,a,b;
		scanf("%d %d %d",&op,&a,&b);
		if(op==1)
		printf("%lld\n",Query(a,b,1));
		else Update(a,b,1);
	}
	return 0;
}

K题,贪心就好了,计算每个数的长度,然后减去比长度少1的9,这样的两个数各个位置相加就是最大的。(代码可优化)

#include<bits/stdc++.h>
using namespace std;
#define ll long long  
int main()
{
	int n;
	scanf("%d",&n);
	while(n--)
	{
		ll x;
		scanf("%lld",&x);
		ll cnt=-1,x1=x;
		while(x1)
		{
			x1/=10;
			cnt++;
		}
		int ans=0;
		ans+=cnt*9;
		for(int i=1;i<=cnt;i++)
		{
			x-=9*pow(10,i-1);
		}
		while(x)
		{
			ans+=x%10;
			x/=10;
		}
		printf("%d\n",ans);
	}
}
发布了67 篇原创文章 · 获赞 4 · 访问量 4819

猜你喜欢

转载自blog.csdn.net/weixin_44203780/article/details/89576994