A
最长连续个数
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
int n,a[maxn];
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
int ans=0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
int cnt=1;
while(a[i]==a[i+1] && i<n)
{
i++; cnt++;
}
ans=max(ans,cnt);
}
printf("%d\n",ans);
}
return 0;
}
B
这道题目还蛮有趣
就是当一个a>10*d 一定可以表示出来
简单证明如下:首先10*d-10*d+9 一定都可以表示出来,大于10*d+9的一定可以通过-d来达到这个区间
所以我们只需要暴力去进行计算a<10*d的数字了
这个想法我貌似在一道模拟题中也见过,数据范围很大,看起来并不像是可以暴力dfs的,但是可以证明大于十几的都不需要计算,最后复杂度就在
代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
int t;
scanf("%d",&t);
while(t--)
{
int q,d,x;
scanf("%d%d",&q,&d);
for(int i=1;i<=q;i++)
{
scanf("%d",&x);
if(x>=d*10) printf("YES\n");
else
{
int sum=0,ok=0;
for(int i=1;i<10;i++)
if((i*d)%10==x%10 && i*d<=x) ok=1;
if(!ok) printf("NO\n");
else printf("YES\n");
}
}
}
return 0;
}
C
这道题目只需要手动模拟几组就可以很轻松的得到公式了,要注意先不妨设一下相对大小来避免绝对值的讨论,然后呢,就是通过一对一对从大到小的计算,注意要验证算出来的数的确是递增的才可以!
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
ll a[maxn],b[maxn];
int n;
bool cmp(ll x,ll y)
{
return x>y;
}
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=2*n;i++) scanf("%lld",&a[i]);
sort(a+1,a+2*n+1,cmp);
int j=1,ok=0;
ll sum=0,last=0,now=0;
for(int i=n;i>=1;i--)
{
if(a[j]!=a[j+1] || (a[j]-last)%(1LL*i*2)!=0)
{
ok=1;
break;
}
now=(a[j]-last)/(1LL*i*2);
b[i]=now;
last+=2*now;
j+=2;
}
for(int i=1;i<=n;i++) if(b[i]<=b[i-1]) ok=1;
if(!ok) printf("YES\n");
else printf("NO\n");
}
return 0;
}
D
题意:给出一个序列,你可以任意挑选两个数x,y将2*x-y加入序列中,询问在是否可以在序列中得到k
首先可以把2*x-y看成x+(x-y)这也就是每个数加上它与另外一个数的差,所以我们只需要考虑能否将ai通过加上差值得到k
由于a3-a1这种的可以转换为a3-a2+a2-a1,所以我们需要考虑的只有相邻两个数的差值,然后由于n个数之间的裴蜀定理,就可以证明出来,只需要证明(k-a[1])% gcd(delta(ai+1-ai) =0 即可
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int n;
ll k,a[maxn],d[maxn];
ll gcd(ll x,ll y)
{
return (!y)?x:gcd(y,x%y);
}
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%lld",&n,&k);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
sort(a+1,a+n+1);
for(int i=1;i<n;i++) d[i]=a[i+1]-a[i];
ll g=d[1];
for(int i=2;i<n;i++) g=gcd(g,d[i]);
if((k-a[1])%g==0) printf("YES\n");
else printf("NO\n");
}
return 0;
}
E
发现按时间逆序之后,每次修改后要保证这个区间同色。
因为一次只能修改小于 len/2个数字,所以一定是修改成数量比较多的那种数字,所以直接用线段树打区间覆盖维护区间和就行了。
特别地,区间查询发现如果 01 数量相同则输出 NO,如果最终状态不符合初始状态也是 NO。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int n,m;
int s[maxn],f[maxn],xx[maxn],yy[maxn];
struct tree
{
int l,r,sum,lz;
}tr[maxn<<2];
void pushup(int now)
{
tr[now].sum=tr[now<<1].sum+tr[now<<1|1].sum;
}
void pushdown(int now)
{
if(tr[now].lz==-1) return;
int v=tr[now].lz;
tr[now<<1].lz=v; tr[now<<1|1].lz=v;
tr[now<<1].sum=(tr[now<<1].r-tr[now].l+1)*v;
tr[now<<1|1].sum=(tr[now<<1|1].r-tr[now<<1|1].l+1)*v;
tr[now].lz=-1;
}
void build(int now,int l,int r)
{
tr[now]=(tree){l,r,0,-1};
if(l==r)
{
tr[now].sum=f[l];
return;
}
int mid=l+r>>1;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
pushup(now);
}
int query(int now,int l,int r)
{
if(tr[now].l>=l && tr[now].r<=r) return tr[now].sum;
pushdown(now);
int mid=tr[now].l+tr[now].r>>1;
int res=0;
if(l<=mid) res+=query(now<<1,l,r);
if(mid<r) res+=query(now<<1|1,l,r);
return res;
}
void update(int now,int l,int r,int v)
{
if(l<=tr[now].l && tr[now].r<=r)
{
tr[now].lz=v;
tr[now].sum=(tr[now].r-tr[now].l+1)*tr[now].lz;
return;
}
pushdown(now);
int mid=tr[now].r+tr[now].l>>1;
if(l<=mid) update(now<<1,l,r,v);
if(mid<r) update(now<<1|1,l,r,v);
pushup(now);
}
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%1d",&s[i]);
for(int i=1;i<=n;i++) scanf("%1d",&f[i]);
for(int i=1;i<=m;i++) scanf("%d%d",&xx[i],&yy[i]);
build(1,1,n);
int flag=0;
for(int i=m;i>=1;i--)
{
int l=xx[i],r=yy[i];
int len=r-l>>1;
int one=query(1,l,r);
int zero=r-l+1-one;
if(zero<=len) update(1,l,r,1);
else if(one<=len) update(1,l,r,0);
else
{
flag=1;
break;
}
}
if(flag)
{
printf("NO\n");
continue;
}
for(int i=1;i<=n;i++)
if(s[i]!=query(1,i,i))
{
flag=1;
break;
}
if(flag) printf("NO\n");
else printf("YES\n");
}
return 0;
}
F
贪心的考虑每次取最远的,看是否满足即可
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5005;
int n;
ll x[maxn],y[maxn];
int ans[maxn],vis[maxn];
ll calc_dis(int a,int b)
{
return (x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]);
}
ll calc_dot(ll a,ll b,ll c,ll d)
{
return a*c+b*d;
}
int judge(int a,int b,int c)
{
if(calc_dot(x[b]-x[a],y[b]-y[a],x[b]-x[c],y[b]-y[c])<0)
return 1;
return 0;
}
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld%lld",&x[i],&y[i]);
int x1=x[1],y1=y[1],last=1;
vis[1]=1; ans[1]=1;
for(int i=2;i<=n;i++)
{
ll dis=0,point=-1;
for(int j=2;j<=n;j++)
{
if(vis[j]) continue;
if(dis<calc_dis(last,j))
{
dis=calc_dis(last,j);
point=j;
}
}
if(i>=3 && judge(ans[i-2],ans[i-1],point)==1)
{
printf("-1\n");
return 0;
}
last=point;
vis[point]=1;
ans[i]=point;
}
for(int i=1;i<=n;i++) printf("%d ",ans[i]);
return 0;
}