A.平方数
讨论一下最接近它的两个平方数即可。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
int main()
{
IO;
int T=1;
//cin>>T;
while(T--)
{
ll x;
cin>>x;
ll y=sqrt(x);
ll z=y+1;
z*=z;
y*=y;
if(abs(y-x)<abs(z-x)) cout<<y<<'\n';
else cout<<z<<'\n';
}
return 0;
}
B.异或图
首先我们要知道一个性质
x
⊕
x
=
0
x\oplus x=0
x⊕x=0
设起点为
s
s
s,终点为
t
t
t,如果存在一条路径
s
−
>
p
1
−
>
p
2
−
>
p
i
−
>
e
s->p_1->p_2->p_i->e
s−>p1−>p2−>pi−>e那么说明有以下等式
a
[
s
]
⊕
a
[
p
1
]
=
k
a
[
p
1
]
⊕
a
[
p
2
]
=
k
a
[
p
2
]
⊕
a
[
p
i
]
=
k
a
[
p
i
]
⊕
a
[
t
]
=
k
a[s]\oplus a[p_1]=k \\ a[p_1]\oplus a[p_2]=k \\a[p_2]\oplus a[p_i]=k\\ a[p_i]\oplus a[t]=k
a[s]⊕a[p1]=ka[p1]⊕a[p2]=ka[p2]⊕a[pi]=ka[pi]⊕a[t]=k我们不难发现如果有一条路径能够使得
s
−
>
⋯
−
>
t
s->\dots->t
s−>⋯−>t说明
a
[
s
]
⊕
a
[
e
]
=
0
/
k
a[s] \oplus a[e]=0/k
a[s]⊕a[e]=0/k,并且明显如果
a
[
s
]
⊕
a
[
e
]
=
k
a[s] \oplus a[e]=k
a[s]⊕a[e]=k答案是
1
1
1,如果
a
[
s
]
⊕
a
[
e
]
=
0
a[s] \oplus a[e]=0
a[s]⊕a[e]=0需要判断是否有中间点即
a
[
e
]
⊕
k
a[e]\oplus k
a[e]⊕k是否存在即可,如存在答案是
2
2
2,否则不存在路径答案是
−
1
-1
−1
刚开始以为
2
20
2^{20}
220很大数组开不下,用unordered_map
存的个数,结果一直T,最后发现数组能开下直接就A了。~。·
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1100010;
int a[N],cnt[N];
int n,q;
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
cnt[a[i]]++;
}
while(q--)
{
int k,st,ed;
scanf("%d%d%d",&k,&st,&ed);
if((a[st]^a[ed])==k) printf("1\n");
else
{
int x=a[st]^k,y=a[ed]^k;
if(x!=y||!cnt[x]) printf("-1\n");
else printf("2\n");
}
}
return 0;
}
C.公因子
辗转相除法扩展可得以下式子,然后不难乱搞求解
g
c
d
(
a
1
,
a
2
,
a
3
,
…
,
a
n
)
=
g
c
d
(
a
1
,
a
2
−
a
1
,
a
3
−
a
2
,
…
,
a
n
−
a
n
−
1
)
gcd(a_1,a_2,a_3,\dots,a_n)=gcd(a_1,a_2-a_1,a_3-a_2,\dots,a_n-a_{n-1})
gcd(a1,a2,a3,…,an)=gcd(a1,a2−a1,a3−a2,…,an−an−1)
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1100010;
ll a[N];
int n;
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
int main()
{
IO;
int T=1;
//cin>>T;
while(T--)
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+1+n);
ll d=a[2]-a[1];
for(int i=3;i<=n;i++) d=gcd(d,a[i]-a[i-1]);
if(d<0) d=-d;
ll res=abs(a[1]/d*d-a[1]);
cout<<d<<' '<<res<<'\n';
}
return 0;
}
E.骚区间
参考大佬题解
一般这种区间左右端点都不确定的情况,我们尝试固定一段点,求另一个端点的可行范围。
对于i
位置作为左端点,考虑如何求右端点的合法区间,由于a[i]
是第二小值,在[i+1,n]
范围内第一个小于a[i]
的位置是l1
,在[i+1,n]
范围内第二个小于a[i]
的位置是r1
,不难看出对于[l1,r1)
范围满足左区间限制条件。
对于i
位置作为右端点,我们同样可以如法炮制的求出满足右端点限制条件的区间(l2,r2]
。
我们可以维护一个树状数组差分求得答案。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1000010;
int a[N],n;
struct node
{
int l,r;
int mx,mn;
}tree[N*4];
void pushup(int u)
{
tree[u].mx=max(tree[u<<1].mx,tree[u<<1|1].mx);
tree[u].mn=min(tree[u<<1].mn,tree[u<<1|1].mn);
}
void build(int u,int l,int r)
{
tree[u]={l,r,0,n+1};
if(l==r)
{
tree[u].mx=tree[u].mn=a[l];
return;
}
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
int query_min(int u,int l,int r,int x)
{
if(l>r) return n+1;
if(tree[u].mn>=x) return n+1;
if(tree[u].l==tree[u].r) return tree[u].l;
int mid=tree[u].l+tree[u].r>>1;
if(l>mid) return query_min(u<<1|1,l,r,x);
else if(r<=mid) return query_min(u<<1,l,r,x);
else
{
if(tree[u<<1].mn<x)
{
int v=query_min(u<<1,l,r,x);
return v!=n+1?v:query_min(u<<1|1,l,r,x);
}
else
return query_min(u<<1|1,l,r,x);
}
}
int query_max(int u,int l,int r,int x)
{
if(l>r) return 0;
if(tree[u].mx<=x) return 0;
if(tree[u].l==tree[u].r) return tree[u].l;
int mid=tree[u].l+tree[u].r>>1;
if(l>mid) return query_max(u<<1|1,l,r,x);
else if(r<=mid) return query_max(u<<1,l,r,x);
else
{
if(tree[u<<1|1].mx>x)
{
int v=query_max(u<<1|1,l,r,x);
return v?v:query_max(u<<1,l,r,x);
}
else
return query_max(u<<1,l,r,x);
}
}
vector<int> p[N];
int cnt[N];
int lowbit(int x)
{
return x&-x;
}
void update(int k,int x)
{
for(;k<=n;k+=lowbit(k)) cnt[k]+=x;
}
ll query(int k)
{
ll now=0;
for(;k;k-=lowbit(k)) now+=cnt[k];
return now;
}
int main()
{
int T=1;
//cin>>T;
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,1,n);
ll res=0;
for(int i=1;i<=n;i++)
{
int l=query_min(1,i+1,n,a[i]);
int r=query_min(1,l+1,n,a[i]);
if(l!=n+1) p[l].push_back(i);
if(r!=n+1) p[r].push_back(-i);
for(auto t:p[i])
{
if(t>0) update(t,1);
else update(-t,-1);
}
r=query_max(1,1,i-1,a[i]);
l=query_max(1,1,r-1,a[i]);
res+=query(r)-query(l);
}
printf("%lld\n",res);
}
return 0;
}
要加油哦~