赞
踩
给你一个序列,你可以选择一个严格递增序列划分成一组,问你最少只需要划分几组。典型的贪心问题,划分成一组时尽可能地把能加入的元素都加入当前的序列中。
#include<bits/stdc++.h> #define close ios::sync_with_stdio(false) using namespace std; int a[110],vis[110]; int main() { close; int T;cin>>T; while(T--) { int n;cin>>n; for(int i=1;i<=n;++i) cin>>a[i]; memset(vis,0,sizeof(vis)); int ans=0; while(1) { bool ok=false;int cur=0; for(int i=1;i<=n;++i) if(!vis[i] && a[i]>cur) cur=a[i],vis[i]=1,ok=true; if(ok) ans++; else break; } cout<<ans<<endl; } }
给定一个数
d
d
d,当
a
i
a_i
ai在他的十进制表示中,
d
d
d出现了至少一次,这个数就是幸运数字。而题目要求的是求解对于给定的元素
x
x
x,这个数是否本身是幸运数字或者可以表示为一系列幸运数字的和。
我们首先要发现这样一个规律:①当
x
≥
10
∗
d
x\geq10*d
x≥10∗d时一定是“YES”。因为当两个数的十位数不同时,他们的差最小是2,最大是18。
[
d
∗
10
,
d
∗
10
+
9
]
[d*10,d*10+9]
[d∗10,d∗10+9]区间的数是幸运数字,而大于这些数的时候,总能通过这些幸运数字加上若干个
d
d
d形成(因为上述的幸运区间的跨度是10,恒大于
d
d
d,因此能做到全覆盖)。②而当
x
<
10
∗
d
x<10*d
x<10∗d的时候情况就有些许复杂,造成该现象的原因是一些个位出现了
d
d
d的数字造成构成的数字不是
d
d
d的倍数(例如
d
=
3
d=3
d=3时,
16
=
13
+
3
16=13+3
16=13+3)我们暴力判断即可。
#include<bits/stdc++.h> #define close ios::sync_with_stdio(false) using namespace std; bool Judge(int x,int d) { if(x<=0) return false; while(x){if(x%10==d) return true;return false;} } bool Solve(int x,int d) { if(x>=d*10 || Judge(x,d)) return true; while(x>0){x-=d;if(Judge(x,d)) return true;} return false; } int main() { close;int T;cin>>T; while(T--) { int q,d;cin>>q>>d; for(int i=1;i<=q;++i) { int x;cin>>x; if(Solve(x,d)) cout<<"YES"<<endl; else cout<<"NO"<<endl; } } }
给定序列
d
d
d,满足
d
i
=
∑
j
=
1
2
n
∣
a
i
−
a
j
∣
d_i=\sum_{j=1}^{2n} |a_i-a_j|
di=∑j=12n∣ai−aj∣;而序列
a
a
a满足:①
2
n
2n
2n个元素互不相同;②对于任意的元素
a
i
a_i
ai,一定在原序列中存在
−
a
i
-a_i
−ai.问这样的序列
a
a
a是否存在。
我们可以通过计算比较出序列
d
d
d的值和点坐标的关系。例如下面的八个点:
八个点关于坐标原点两两对称,我们计算后面四个点的
d
i
d_i
di,分别是:
d
1
=
(
x
1
+
x
2
+
x
3
+
x
4
)
∗
2
d_1=(x_1+x_2+x_3+x_4)*2
d1=(x1+x2+x3+x4)∗2
d
2
=
(
x
2
+
x
2
+
x
3
+
x
4
)
∗
2
d_2=(x_2+x_2+x_3+x_4)*2
d2=(x2+x2+x3+x4)∗2
d
3
=
(
x
3
+
x
3
+
x
3
+
x
4
)
∗
2
d_3=(x_3+x_3+x_3+x_4)*2
d3=(x3+x3+x3+x4)∗2
d
4
=
(
x
4
+
x
4
+
x
4
+
x
4
)
∗
2
d_4=(x_4+x_4+x_4+x_4)*2
d4=(x4+x4+x4+x4)∗2很容易发现可以从最后一个方程开始,依次倒推去解
x
4
,
x
3
,
x
2
,
x
1
x_4,x_3,x_2,x_1
x4,x3,x2,x1,只要能有正整数解,同时各个解互不相同,说明这个答案是成立的,即我们能找到这样的序列
a
a
a.
#include<bits/stdc++.h> #define close ios::sync_with_stdio(false) using namespace std; const int maxn=2e5+100; typedef long long ll; ll a[maxn];int n; bool solve() { sort(a+1,a+2*n+1); for(int i=1;i<=2*n;i+=2) if(a[i]&1 || a[i]!=a[i+1]) return false; if(a[2*n]%(2*n)!=0) return false; ll last=a[2*n]/(n*2),sum=last; if(last==0) return false; for(int i=n-1;i>0;--i) { if((a[2*i]-sum*2)%(2*i)!=0) return false; ll cur=(a[2*i]-sum*2)/(2*i); if(cur>=last || cur<=0) return false; last=cur;sum+=cur; } return true; } int main() { close;int T;cin>>T; while(T--) { cin>>n; for(int i=1;i<=2*n;++i) cin>>a[i]; if(solve()) cout<<"YES"<<endl; else cout<<"NO"<<endl; } }
题目的意思是给定
n
n
n个不同的数
x
i
x_i
xi,能否通过不断选取
x
,
y
x,y
x,y,并加入新的元素
2
x
−
y
2x-y
2x−y的方式,最后构造出
k
k
k.
这个题本质上是在考察扩展欧几里得算法:对于
a
,
b
a,b
a,b来说,一定能找到
q
,
r
q,r
q,r使得
a
=
q
∗
b
+
r
a=q*b+r
a=q∗b+r成立。而求解最大公因数就是采用辗转相除的方式,算法的终点就是
a
=
=
g
c
d
,
b
=
=
0
a==gcd,b==0
a==gcd,b==0.得到0对于这个题是毫无意义的,而gcd应该是我们能够得到的最小的数。而
2
x
−
y
2x-y
2x−y本质上就是在模拟辗转相除,例如令
y
=
q
x
+
r
y=qx+r
y=qx+r,那么经过不断地变化我们能够得到
r
(
q
为
偶
数
)
或
者
−
x
+
r
(
q
为
奇
数
)
r(q为偶数)或者-x+r(q为奇数)
r(q为偶数)或者−x+r(q为奇数),而前面的
x
x
x有或者无都不影响gcd的求解,即
g
c
d
(
−
x
+
r
,
x
)
=
=
g
c
d
(
r
,
x
)
gcd(-x+r,x)==gcd(r,x)
gcd(−x+r,x)==gcd(r,x)。因此,我们只要找到上述所有相邻元素的差值,并求解gcd,就是在求解变换的最小步长。只要
(
k
−
a
[
1
]
)
%
s
t
e
p
m
i
n
=
=
0
(k-a[1])\%step_{min}==0
(k−a[1])%stepmin==0,则该变换能够做到。
#include<bits/stdc++.h> #define close ios::sync_with_stdio(false) using namespace std; typedef long long ll; const int maxn=2e5+100; ll a[maxn]; int main() { close;int T;cin>>T; while(T--) { ll n,k;cin>>n>>k; for(int i=1;i<=n;++i) cin>>a[i]; sort(a+1,a+n+1); ll min_minus=0; for(int i=1;i<n;++i) min_minus=__gcd(min_minus,a[i+1]-a[i]); if((k-a[1])%min_minus==0) cout<<"YES"<<endl; else cout<<"NO"<<endl; } }
题目的意思是给定起始字符串和终止字符串,然后给出q组区间,每次先比较该区间是否都是相同的数字,然后可以对该区间进行修改,但修改的个数必须严格小于长度的一半,问最终能否达到终止字符串。
这个题的关键在于反向思维,给你终止字符串,反向给你询问区间,你先修改这个区间使其变成相同的数字,然后再由对方判断,最终如果能到达起始字符串就输出“YES”,反向思维的好处是在于这种情况下做出的修改的方式是唯一的。需要注意一个细节,但询问的区间长度是偶数时,而恰好0,1的数量各占一半,这种情况没有办法作出修改,一定无法让区间全为一种数字,直接输出“NO”。
区间覆盖成一种数字可以采用线段树的方式,最终的复杂度是
O
(
(
n
+
q
)
l
o
g
n
)
O((n+q)logn)
O((n+q)logn).
#include<bits/stdc++.h> #define close ios::sync_with_stdio(false) using namespace std; const int maxn=2e5+100; int before[maxn],after[maxn],tree[maxn*4],mark[maxn*4],n,q; char be[maxn],af[maxn]; struct Rec{ int l,r; }rec[maxn]; void push_down(int p,int len) { if(mark[p]==-1) return; mark[2*p]=mark[p];mark[2*p+1]=mark[p]; tree[2*p]=mark[p]*(len-len/2); tree[2*p+1]=mark[p]*(len/2); mark[p]=-1; } void build(int l=1,int r=n,int p=1) { if(l==r) tree[p]=after[l]; else{ int mid=(l+r)/2; build(l,mid,2*p); build(mid+1,r,2*p+1); tree[p]=tree[p*2]+tree[p*2+1]; } } void update(int l,int r,int d,int p=1,int cl=1,int cr=n) { if(l>cr || r<cl) return; if(l<=cl && cr<=r) { tree[p]=d*(cr-cl+1); if(cr>cl) mark[p]=d; } else{ int mid=(cl+cr)/2; push_down(p,cr-cl+1); update(l,r,d,p*2,cl,mid); update(l,r,d,p*2+1,mid+1,cr); tree[p]=tree[p*2]+tree[p*2+1]; } } int query(int l,int r,int p=1,int cl=1,int cr=n) { if(l>cr || r<cl) return 0; if(l<=cl && cr<=r) return tree[p]; else{ int mid=(cl+cr)/2; push_down(p,cr-cl+1); return query(l,r,2*p,cl,mid)+query(l,r,2*p+1,mid+1,cr); } } bool solve() { scanf("%d%d",&n,&q); scanf("%s",be);scanf("%s",af); for(int i=0;i<n;++i) before[i+1]=be[i]-'0',after[i+1]=af[i]-'0'; for(int i=0;i<=4*n+10;++i) mark[i]=-1; build(); for(int i=1;i<=q;++i) scanf("%d%d",&rec[i].l,&rec[i].r); for(int i=q;i>0;--i) { int cur=query(rec[i].l,rec[i].r),len=rec[i].r-rec[i].l+1; if(len%2==0){ if(cur*2==len) return false; if(cur*2>len) update(rec[i].l,rec[i].r,1); else update(rec[i].l,rec[i].r,0); } else{ if(cur*2>len) update(rec[i].l,rec[i].r,1); else update(rec[i].l,rec[i].r,0); } } for(int i=1;i<=n;++i) if(query(i,i)!=before[i]) return false; return true; } int main() { close;int T;scanf("%d",&T); while(T--) { if(solve()) printf("YES\n"); else printf("NO\n"); } }
题目要求给出一个序列,使得序列中任意三个连续的顶点
A
,
B
,
C
A,B,C
A,B,C,构成的三角形(可以退化成一条边)中,
∠
B
<
9
0
∘
\angle B<90^\circ
∠B<90∘。
这道题可以理解成一个三角形的定理:三角形中最多有一个钝角或者直角,而且一定是最长边所对应的角。因此,我们可以任选一个点作为起点,每轮迭代都找一条最长的边,那么这条边与其他边所夹的角一定是锐角。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=5e3+100; struct Point{ ll x,y; }P[maxn]; int vis[maxn]; double GetDistance(int i,int j) {return sqrt((P[i].x-P[j].x)*(P[i].x-P[j].x)+(P[i].y-P[j].y)*(P[i].y-P[j].y));} int main() { int n;scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%lld%lld",&P[i].x,&P[i].y); memset(vis,0,sizeof(vis)); printf("1");vis[1]=1; int cur_id=1; for(int i=2;i<=n;++i) { double max_dis=0.0;int next_id; for(int i=1;i<=n;++i) { if(vis[i]) continue; double cur_dis=GetDistance(cur_id,i); if(cur_dis>max_dis) max_dis=cur_dis,next_id=i; } printf(" %d",next_id); cur_id=next_id;vis[next_id]=1; } }
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。