2022/3/4
A. Parity
题意:
求
n
=
a
1
∗
b
k
−
1
+
a
2
∗
b
k
−
2
+
.
.
.
+
a
k
n=a_1*b^{k-1}+a_2*b^{k-2}+...+a_k
n=a1∗bk−1+a2∗bk−2+...+ak的奇偶性。
题解:
考虑b的奇偶性,若b为偶数,则前k-1项必为偶数,此时只用判断
a
k
a_k
ak奇偶性。若b为奇数,n的奇偶性只与
∑
i
−
1
k
a
i
\sum_{i-1}^ka_i
∑i−1kai有关。
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
#include <iomanip>
#include <deque>
#include <time.h>
#include <bitset>
using namespace std;
#define ll long long
#define maxn 300200
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}
int a[maxn];
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int b,k;
cin>>b>>k;
for(int i=1;i<=k;i++)cin>>a[i];
if(b%2==0){
if(a[k]%2)cout<<"odd";
else cout<<"even";
}
else{
int sum=0;
for(int i=1;i<=k;i++){
sum+=a[i]%2;
}
sum%=2;
if(sum)cout<<"odd";
else cout<<"even";
}
return 0;
}
B. Tape
题意:
有一个m长的棍子,有n除断裂,你有k个胶带,求所需胶带的最小长度。
题解:
考虑1个胶带若匹配一个断裂,所需长度为1,还剩下n-k个断裂,每个断裂所需要的贡献为
p
o
s
i
−
p
o
s
i
−
1
pos_i-pos_{i-1}
posi−posi−1。对差值排序,取最小的n-k个贡献。
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
#include <iomanip>
#include <deque>
#include <time.h>
#include <bitset>
using namespace std;
#define ll long long
#define maxn 300200
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}
int a[maxn];
int n,m,k;
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin>>n>>m>>k;
for(int i=1;i<=n;i++)cin>>a[i];
vector<int>v;
for(int i=2;i<=n;i++)v.push_back(a[i]-a[i-1]-1);
sort(v.begin(),v.end());
int ans=0;
for(int i=0;i<n-k;i++)ans+=v[i];
cout<<ans+n<<"\n";
return 0;
}
C. Meaningless Operations
题意:
求
f
(
a
)
=
m
a
x
0
<
b
<
a
g
c
d
(
a
⨁
b
,
a
&
b
)
f(a)=max_{0<b<a}gcd(a\bigoplus{b},a\&b)
f(a)=max0<b<agcd(a⨁b,a&b)
题解:
考虑
a
⨁
b
=
(
a
∣
b
)
−
(
a
&
b
)
,
g
c
d
(
a
⨁
b
,
a
&
b
)
=
g
c
d
(
a
∣
b
,
a
&
b
)
a\bigoplus{b}=(a|b)-(a\&b),gcd(a\bigoplus{b},a\&b)=gcd(a|b,a\&b)
a⨁b=(a∣b)−(a&b),gcd(a⨁b,a&b)=gcd(a∣b,a&b)
若a不为
2
n
−
1
2^n-1
2n−1,则
a
∣
b
=
2
n
−
1
,
a
&
b
=
0
a|b=2^n-1,a\&b=0
a∣b=2n−1,a&b=0时,gcd最大为a。
若a为
2
n
−
1
2^n-1
2n−1,则b无论取什么,
a
∣
b
=
a
a|b=a
a∣b=a而
a
&
b
a\&b
a&b可以取[1,a-1].gcd最大时就是a/(除了a的最大的因子)。
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
#include <iomanip>
#include <deque>
#include <time.h>
#include <bitset>
using namespace std;
#define ll long long
#define maxn 300200
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int q;
cin>>q;
while(q--){
ll nn;
cin>>nn;
ll x=1;
while(x<=nn)x*=2ll;
if(x-1ll==nn){
ll n=nn;
vector<int>ans;
for(int i=2;i*i<=n;i++){
if(n%i==0){
while(n%i==0)ans.push_back(i),n/=i;
}
}
if(n>1)ans.push_back(n);
sort(ans.begin(),ans.end());
cout<<nn/ans[0]<<"\n";
}
else cout<<x-1ll<<"\n";
}
return 0;
}
D. Jongmah
题意:
有n个牌,牌上的数字为[1,m],三个一样的数字或者三个连续的数字可以凑为一组,问最多可以凑多少组。
题解:
对于每张牌,有四个方案,
(
i
,
i
,
i
)
,
(
i
,
i
+
1
,
i
+
2
)
,
(
i
−
1
,
i
,
i
+
1
)
,
(
i
−
2
,
i
−
1
,
i
)
(i,i,i),(i,i+1,i+2),(i-1,i,i+1),(i-2,i-1,i)
(i,i,i),(i,i+1,i+2),(i−1,i,i+1),(i−2,i−1,i)
后面三个方案数不会超过3,一旦超过3,那么每张牌可以自己三个一组。
考虑dp。
dp[i][j][k]表示到第i张牌时,使用3方案j个,使用2方案k个。
dp[i][k][l]=dp[i-1][j][k]+l+(num[i]-j-k-l)/3.
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
#include <iomanip>
#include <deque>
#include <time.h>
#include <bitset>
using namespace std;
#define ll long long
#define maxn 1000200
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}
ll dp[maxn][4][4],num[maxn];
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int n,m;
cin>>n>>m;
for(int i=1,x;i<=n;i++){
cin>>x;
num[x]++;
}
for(int i=1;i<=m;i++){
for(int j=0;j<3;j++){
for(int k=0;k<3;k++){
for(int l=0;l<3&&j+k+l<=num[i];l++){
dp[i][k][l]=max(dp[i][k][l],dp[i-1][j][k]+l+(num[i]-j-k-l)/3);
}
}
}
}
cout<<dp[m][0][0];
return 0;
}
E. Magic Stones
题意:
有两个数组
c
,
t
c,t
c,t.对于i为[2,n-1]的数,你可以令
c
i
=
c
i
−
1
+
c
i
+
1
−
c
i
c_i=c_{i-1}+c_{i+1}-c_i
ci=ci−1+ci+1−ci
问能否将
c
c
c数组变为
t
t
t数组.
题解:
一次操作后,实际上
c
i
c_i
ci仅仅对于
(
c
i
−
1
+
c
i
+
1
)
/
2
(c_{i-1}+c_{i+1})/2
(ci−1+ci+1)/2对称.
也就是差值
c
i
+
1
−
c
i
,
c
i
−
c
i
−
1
c_{i+1}-c_i,c_i-c_{i-1}
ci+1−ci,ci−ci−1对换。但是差值不会改变,数量也不变,只需要比较下差值是否完全一致,以及
c
1
=
=
t
1
c_1==t_1
c1==t1。
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
#include <iomanip>
#include <deque>
#include <time.h>
#include <bitset>
using namespace std;
#define ll long long
#define maxn 1000200
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}
int a[maxn],b[maxn];
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int n;
vector<int>ans1,ans2;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
for(int i=2;i<=n;i++){
ans1.push_back(a[i]-a[i-1]);
ans2.push_back(b[i]-b[i-1]);
}
sort(ans1.begin(),ans1.end());
sort(ans2.begin(),ans2.end());
if(a[1]==b[1]&&ans1==ans2)cout<<"Yes\n";
else cout<<"No\n";
return 0;
}
F. Nearest Leaf
题意:
有一颗以1为根的树,两点之间的距离就是边权相加的和。询问q次,每次问所有dfs序在[l,r]内的叶子节点距离v结点的最短路径。
题解:
对与每个点u,若叶子结点v是他的儿子,他的路径就是
d
i
s
(
u
,
v
)
=
d
i
s
(
1
,
v
)
−
d
i
s
(
1
,
u
)
dis(u,v)=dis(1,v)-dis(1,u)
dis(u,v)=dis(1,v)−dis(1,u),否则
d
i
s
(
u
,
v
)
=
d
i
s
(
1
,
v
)
+
d
i
s
(
1
,
u
)
dis(u,v)=dis(1,v)+dis(1,u)
dis(u,v)=dis(1,v)+dis(1,u)。判断是否是儿子结点可以用dfs序来判断,贡献用线段树区间维护,离线查询。
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
#include <iomanip>
#include <deque>
#include <time.h>
#include <bitset>
using namespace std;
#define ll long long
#define maxn 500200
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}
int n,m,cnt,l[maxn],r[maxn],siz[maxn];
ll ans[maxn],a[maxn],dis[maxn];
vector<pair<int,int> >g[maxn];
struct node{
int id,l,r;
node(int a,int b,int c){
id=a;
l=b;
r=c;
}
};
vector<node >q[maxn];
void dfs1(int u){
l[u]=++cnt;
siz[u]=1;
for(auto &it:g[u]){
int v=it.first,w=it.second;
dis[v]=dis[u]+w;
dfs1(v);
siz[u]+=siz[v];
}
r[u]=l[u]+siz[u]-1;
}
ll tree[maxn<<2];
ll lazy[maxn<<2];
void pushup(int id){
tree[id]=min(tree[id<<1],tree[id<<1|1]);
}
void pushdown(int id){
if(!lazy[id])return ;
tree[id<<1]+=lazy[id];
tree[id<<1|1]+=lazy[id];
lazy[id<<1]+=lazy[id];
lazy[id<<1|1]+=lazy[id];
lazy[id]=0;
return;
}
void build(int id,int l,int r){
if(l==r){
tree[id]=a[l];
return ;
}
// printf("%d %d\n",l,r);
int mid=(l+r)>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
pushup(id);
}
void update(int id,int l,int r,int lx,int ly,ll val){
if(l>=lx&&r<=ly){
tree[id]+=val;
lazy[id]+=val;
return ;
}
pushdown(id);
int mid=(l+r)>>1;
if(mid>=lx)update(id<<1,l,mid,lx,ly,val);
if(mid<ly)update(id<<1|1,mid+1,r,lx,ly,val);
pushup(id);
}
ll query(int id,int l,int r,int lx,int ly){
if(l>=lx&&r<=ly)return tree[id];
pushdown(id);
int mid=(l+r)>>1;
ll ans=inf;
if(mid>=lx)ans=min(ans,query(id<<1,l,mid,lx,ly));
if(mid<ly)ans=min(ans,query(id<<1|1,mid+1,r,lx,ly));
return ans;
}
void dfs2(int u){
for(auto &it:q[u]) {
ans[it.id]=query(1,1,n,it.l,it.r);
}
for(auto &it:g[u]){
int v=it.first,w=it.second;
update(1,1,n,1,n,w);
update(1,1,n,l[v],r[v],-2*w);
dfs2(v);
update(1,1,n,1,n,-w);
update(1,1,n,l[v],r[v],2*w);
}
}
int main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin>>n>>m;
for(int i=2,u,v;i<=n;i++){
cin>>u>>v;
g[u].push_back(make_pair(i,v));
}
// for(auto &x:g)sort(x.begin(),x.end());
for(int i=1,v,l,r;i<=m;i++){
cin>>v>>l>>r;
q[v].push_back({i,l,r});
}
dfs1(1);
// printf("111\n");
for(int i=1;i<=n;i++){
if(siz[i]==1)a[i]=dis[i];
else a[i]=inf;
}
build(1,1,n);
// printf("2222\n");
dfs2(1);
for(int i=1;i<=m;i++){
cout<<ans[i]<<"\n";
}
return 0;
}