A - A+…+B Problem
模拟题意
#include<bits/stdc++.h>
using namespace std;
int n,a,b;
int main(){
scanf("%d %d %d",&n,&a,&b);
if(a==b || a<b && n>=2) printf("%lld\n",1ll*(n-2)*(b-a)+1);
else printf("0\n");
}
B - Evilator
模拟题意
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
char s[N];
int n;
int main(){
scanf("%s",s+1);n=strlen(s+1);
long long tot=0;
for(int i=1;i<=n;i++)
if(s[i]=='U') tot+=n-1+i-1;
else tot+=n-1+n-i;
printf("%lld\n",tot);
}
C - Nuske vs Phantom Thnook
保证是树了,用二维前缀和维护点数,横向连边数,纵向连边数即可。
#include<bits/stdc++.h>
using namespace std;
const int N=2010;
int n,m,q,h[N][N],l[N][N],sum[N][N];
char s[N][N];
int main(){
scanf("%d %d %d",&n,&m,&q);
for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) {
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
if(s[i][j]=='1') sum[i][j]++;
}
for(int i=1;i<=n;i++)
for(int j=1;j<m;j++) {
h[i][j]=h[i-1][j]+h[i][j-1]-h[i-1][j-1];
if(s[i][j]=='1' && s[i][j+1]=='1') h[i][j]++;
}
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++) {
l[i][j]=l[i-1][j]+l[i][j-1]-l[i-1][j-1];
if(s[i][j]=='1' && s[i+1][j]=='1') l[i][j]++;
}
int x1,y1,x2,y2;
while(q--){
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);x1--;y1--;
printf("%d\n",sum[x2][y2]+sum[x1][y1]-sum[x1][y2]-sum[x2][y1]-
(h[x2][y2-1]+h[x1][y1]-h[x1][y2-1]-h[x2][y1])-
(l[x2-1][y2]+l[x1][y1]-l[x2-1][y1]-l[x1][y2]));
}
}
D - A or…or B Problem
考虑不相同的最高位为
p
p
p,即
t
=
2
p
t=2^p
t=2p,忽略
A
,
B
>
p
A,B>p
A,B>p的位置。
用
[
A
,
t
)
[A,t)
[A,t)自己或,会生成
[
A
,
t
)
[A,t)
[A,t)。
用
[
t
,
B
]
[t,B]
[t,B]自己或,会生成
[
t
,
2
p
o
s
+
1
)
[t,2^{pos+1})
[t,2pos+1),
p
o
s
pos
pos为
B
B
B除
p
p
p外的最高有
1
1
1位置。
用两个一起或,会生成
[
t
+
A
,
2
t
)
[t+A,2t)
[t+A,2t)。
注意后面两个可能有交,答案三者加起来即可。
#include<bits/stdc++.h>
using namespace std;
long long a,b;
int main(){
scanf("%lld %lld",&a,&b);
int pos=59;
while(pos!=-1 && ((a>>pos)&1)==((b>>pos)&1)) pos--;
if(pos==-1) printf("1\n");
else if(pos==0) printf("2\n");
else{
long long tot=(1ll<<pos);
a&=tot-1;b&=tot-1;
long long ans=tot-a;pos--;
while(pos!=-1 && ((b>>pos)&1)==0) pos--;
ans+=min((1ll<<(pos+1))+tot-a,tot);
printf("%lld\n",ans);
}
}
E - Mr.Aoki Incubator
现将位置和速度都离散化,速度的大小关系恰好是
+
inf
+\inf
+inf时间两两的位置关系。
可以发现,一个点可以覆盖的点是一个以速度大小为下标的区间。
即,位置比当前小且速度最大的点,一定会被覆盖,位置比当前大且速度最小的点,也一定会被覆盖。
两者中间的点要么会自己经过当前点,要么会被这两个点(可能是其中之一)经过。
仔细讨论又会发现:将区间按照对应点的原来位置排序后,左端点右端点都满足不降序。
貌似求两个端点可以直接对于位置顺序遍历搞定,但是博主比较蠢按照速度遍历还写了个树状数组。
读者自证不难。
那么直接前缀和优化
D
p
Dp
Dp即可。
#include<bits/stdc++.h>
using namespace std;
const int N=200010,mod=1000000007;
int n,x[N],v[N],p[N],sum[N],L[N],R[N],a[N],pre[N];
vector<int> V[N];
void add(int x,int t){
while(x<=n){
sum[x]=min(sum[x],t);
x+=(x&(-x));
}
}
int gs(int x){
int tot=1e9;
while(x){
tot=min(tot,sum[x]);
x-=(x&(-x));
}
return tot;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d %d",&x[i],&v[i]);
for(int i=1;i<=n;i++) p[i]=x[i];sort(p+1,p+1+n);
for(int i=1;i<=n;i++) x[i]=lower_bound(p+1,p+1+n,x[i])-p;
for(int i=1;i<=n;i++) p[i]=v[i];sort(p+1,p+1+n);
for(int i=1;i<=n;i++) v[i]=lower_bound(p+1,p+1+n,v[i])-p,a[v[i]]=x[i];
for(int i=1;i<=n;i++) sum[i]=1e9;
for(int i=1;i<=n;i++){
add(n-a[i]+1,i);
L[i]=gs(n-a[i]+1);
}
for(int i=1;i<=n;i++) sum[i]=1e9;
for(int i=n;i>=1;i--){
add(a[i],n-i+1);
R[i]=n-gs(a[i])+1;
V[R[i]].push_back(L[i]);
}
pre[0]=1;
for(int i=1;i<=n;i++){
pre[i]=pre[i-1];
sort(V[i].begin(),V[i].end());
for(int j=0;j<V[i].size();j++)
pre[i]=(2ll*pre[i]+mod-(V[i][j]==1?0:pre[V[i][j]-2]))%mod;
}
printf("%d\n",(pre[n]+mod-pre[n-1])%mod);
}
F - Kenus the Ancient Greek
这种构造结论题应该不是人想的。
首先显然
(
F
[
i
]
,
F
[
i
+
1
]
)
=
i
−
1
(F[i],F[i+1])=i-1
(F[i],F[i+1])=i−1。
定义优秀的数对为
(
x
,
y
)
=
k
(x,y)=k
(x,y)=k,当且仅当
x
,
y
≤
2
∗
F
[
k
+
2
]
x,y\leq2*F[k+2]
x,y≤2∗F[k+2]。
定义好的数对为
(
x
,
y
)
=
k
(x,y)=k
(x,y)=k,当且仅当不存在
x
′
,
y
′
<
x
,
y
x',y'<x,y
x′,y′<x,y且
(
x
′
,
y
′
)
>
k
(x',y')>k
(x′,y′)>k。
可以发现优秀的数对
(
x
,
y
)
=
k
(x,y)=k
(x,y)=k的个数不超过
O
(
k
)
O(k)
O(k)个。
显然要求的所有数对都是好的数对。
如何建立起两者的联系?
定理:一个好的数对经过一次变换之后会变成一个优秀的数对。
如果知道了这件事情,我们就可以暴力枚举值为
a
n
s
−
1
ans-1
ans−1的优秀的数对,计算出值为
a
n
s
ans
ans的好的数对个数。
如何证明?考虑反证法,推出不满足好的数对性质的矛盾即可。
#include<bits/stdc++.h>
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define LL long long
#define mod 1000000007
using namespace std;
const int N=110;
int T;
LL f[N];
vector<pair<LL,LL> > p[N];
int main(){
f[0]=0;f[1]=1;
int t=-1;
for(int i=0;f[i+1]<=1e18;i++) t++,f[i+2]=f[i]+f[i+1];
p[1].pb(mk(1,2));p[1].pb(mk(1,3));p[1].pb(mk(1,4));
for(int i=2;i<=t;i++){
for(int j=0;j<p[i-1].size();j++){
LL a=p[i-1][j].se,b=p[i-1][j].fi+p[i-1][j].se;
p[i].pb(mk(a,b));
while(a+b<=2*f[i+2]) b+=a,p[i].pb(mk(a,b));
}
}
LL x,y;
scanf("%d",&T);
while(T--){
scanf("%lld %lld",&x,&y);
if(x>y) swap(x,y);
int ans=1;
while(x>=f[ans+2] && y>=f[ans+3]) ans++;
printf("%d ",ans);
if(ans==1) printf("%lld\n",1ll*x*y%mod);
else{
ans--;
LL tot=0;
for(int i=0;i<p[ans].size();i++){
if(p[ans][i].se>x) continue;
if(p[ans][i].fi<=y) tot+=(y-p[ans][i].fi)/p[ans][i].se;
if(p[ans][i].fi<=x) tot+=(x-p[ans][i].fi)/p[ans][i].se;
tot%=mod;
}
printf("%lld\n",tot);
}
}
}