这套题是和队友一起做的,我就把我会写的讲一下吧。
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);
}
}