前言
由于A理解错题意导致差点全场崩盘,A想到一个巧妙地方法,但是B由于A耽误太久导致B有二十分钟不知道在写什么,写写改改,最后过了pp还是fst了,感觉CD都很简单,至少比B简单,赛后一发过了B,还是B简单(真香)O(∩_∩)O
rank 881 rating -=16
A. A Prank
题意
给你一个数组,数组大小<100
并且数组有一个性质 1<=a1<a2<a3<...<an<=10001<=a_1<a_2<a_3<...<a_n<=10001<=a1<a2<a3<...<an<=1000
在数组中可以删除连续的一段,但是要保证能按照这个性质还原数组
问删除的那段的最长长度
做法
我们发现只有连续上升超过2,才能删除,删除大小为总上升长度-2
但是首尾处理起来却不太方便
所以我们设a[0]=0;a[n+1]=1001
这样也就避免首首尾需要特判的情况。
代码
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn = 1e5+5;
char str[maxn];
int a[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
a[0]=0;
a[n+1]=1001;
int tmp=1;
int ans=0;
for(int i=1;i<=n+1;i++)
{
if(a[i]==a[i-1]+1) tmp++;
else
{
ans=max(ans,tmp-2);
tmp=1;
}
}
ans=max(ans,tmp-2);
printf("%d\n",ans);
return 0;
}
B. Math
题意
给你一个数,每次可以进行两个操作,乘一个数或者开根
问最少多少次操作能使这个数变得最小
做法
仔细想一下就会发现,如果我们需要乘法再开根,
那么一次就能把所有需要的乘法都乘上,之后不断开根就可以
但是这里有一些细节问题,最终的最小值一定是原数的所有质因子相乘
那么我们要乘之后变成什么值才能一直开根呢
一定是每个质因子都有2k2^k2k个,而且所有质因子的k相等
于是我们先算出最小的满足情况的k是多少,然后答案就是k-1+1
因为需要k-1次开根和一次乘法
但是这里有一个坑点就是,有可能不需要乘法,什么时候不需要乘法呢
就是所有质因子的个数相同而且都是2^k个。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
typedef pair<int,int> pii;
const int maxn = 1e6+10;
set<int> s;
bool check(int x)
{
int i=1;
while(i<=x)
{
if(i==x) return true;
i=i*2;
}
return false;
}
int main()
{
int n;
scanf("%d",&n);
if(n==1)
{
printf("1 0\n");
return 0;
}
int maxx=0;
int ans1=1;
for(int i=2;i<=n;i++)
{
if(n%i==0)
{
ans1=ans1*i;
int num=0;
while(n%i==0) n/=i,num++;
s.insert(num);
maxx=max(maxx,num);
}
}
int tmp=1;
int pos=0;
for(int i=1;;i++)
{
if(tmp>=maxx) break;
pos++;
tmp=tmp*2;
}
int ans=pos+1;
if(s.size()==1&&check(*s.begin()))//所有质因子个数相同而且都是2^k
{
ans--;
}
printf("%d %d\n",ans1,ans);
return 0;
}
C. Banh-mi
题意
题意就是给你一个01串,q次询问每次询问一段区间题意就是给你一个01串,q次询问每次询问一段区间题意就是给你一个01串,q次询问每次询问一段区间
每次询问询问的是:最初区间内0的权值是0,1的权值是1每次询问询问的是:最初区间内0的权值是0,1的权值是1每次询问询问的是:最初区间内0的权值是0,1的权值是1
每次可以移出一个字符,移除后答案加上该字符的权值每次可以移出一个字符,移除后答案加上该字符的权值每次可以移出一个字符,移除后答案加上该字符的权值
其余所有字符加上该字符的权值其余所有字符加上该字符的权值其余所有字符加上该字符的权值
最后询问每个区间内能获得的最大答案,每次查询是独立的最后询问每个区间内能获得的最大答案,每次查询是独立的最后询问每个区间内能获得的最大答案,每次查询是独立的
做法
首先我们发现,对每个区间来说,一定是一直拿1,1没有了拿0这个策略首先我们发现,对每个区间来说,一定是一直拿1,1没有了拿0这个策略首先我们发现,对每个区间来说,一定是一直拿1,1没有了拿0这个策略
所以问题就变为给你一个先1后0的序列来计算上面的问题所以问题就变为给你一个先1后0的序列来计算上面的问题所以问题就变为给你一个先1后0的序列来计算上面的问题
而这个序列中0,1的个数我们都可以通过前缀和快速计算出来而这个序列中0,1的个数我们都可以通过前缀和快速计算出来而这个序列中0,1的个数我们都可以通过前缀和快速计算出来
我们发现对于每个1的区间,对答案的贡献是一段首项为1我们发现对于每个1的区间,对答案的贡献是一段首项为1我们发现对于每个1的区间,对答案的贡献是一段首项为1
公比为2,长度为1的个数等比数列公比为2,长度为1的个数等比数列公比为2,长度为1的个数等比数列
对于每个0的区间,对答案的贡献是一段首项为1那段区间对答案的贡献对于每个0的区间,对答案的贡献是一段首项为1那段区间对答案的贡献对于每个0的区间,对答案的贡献是一段首项为1那段区间对答案的贡献
公比为2,长度为0的个数的等比数列公比为2,长度为0的个数的等比数列公比为2,长度为0的个数的等比数列
之后加个快速幂再加个前缀和预处理这道题就做完了“”之后加个快速幂再加个前缀和预处理这道题就做完了“”之后加个快速幂再加个前缀和预处理这道题就做完了“”
坑点
有减法要加Mod有减法要加Mod%Mod有减法要加Mod
代码
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<map>
#include<bitset>
#include<stack>
#include<set>
#include<vector>
#include <time.h>
#include<string.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <ll, int> pli;
typedef pair <db, db> pdd;
const int maxn = 1e5+5;
const int Mod=1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const double e=exp(1);
const db PI = acos(-1);
const db ERR = 1e-10;
#define Se second
#define Fi first
#define pb push_back
#define dbg(x) cout<<#x<<" = "<< (x)<< endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl
ll pow_(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1) ans=(ans*a)%Mod;
b>>=1;
a=(a*a)%Mod;
}
return ans;
}
ll inv(ll x)
{
return pow_(x,Mod-2);
}
ll sum[maxn][2];
char str[maxn];
int main()
{
//ios::sync_with_stdio(false);
//freopen("a.txt","r",stdin);
//freopen("b.txt","w",stdout);
int n,q;
scanf("%d%d",&n,&q);
scanf("%s",str+1);
for(int i=1;i<=n;i++)
{
sum[i][0]=sum[i-1][0];
sum[i][1]=sum[i-1][1];
if(str[i]=='0') sum[i][0]=(sum[i][0]+1)%Mod;
else sum[i][1]=(sum[i][1]+1)%Mod;;
}
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
ll sum0=(sum[r][0]-sum[l-1][0]+Mod)%Mod;
ll sum1=(sum[r][1]-sum[l-1][1]+Mod)%Mod;
ll ans=0;
ans=(pow_(2,sum1)-1+Mod)%Mod;
ll st=(pow_(2,sum1)-1+Mod)%Mod;
ll tmp=(pow_(2,sum0)-1+Mod)%Mod;
tmp=(tmp*st)%Mod;
ans=(ans+tmp)%Mod;
printf("%lld\n",ans);
}
//cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
return 0;
}
D. Fun with Integers
题意
给你n,让你从2到n这个区间找任意两个数,
使得一个数是另一个的因子,绝对值小的可以变为绝对值大的
问你这变化过程所乘的倍数绝对值之和
做法
看样例就会发现每一对这种数对答案做四次贡献,每次的贡献是倍数
代码
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef long long ll;
int main()
{
ll n,ans=0;
scanf("%lld",&n);
for(ll i=2;i<=n;i++)
{
for(ll j=2;j*i<=n;j++)
{
ans+=4LL*j;
}
}
printf("%lld\n",ans);
return 0;
}
E. Company
题意
给你一颗具有n个节点的树,有q次查询,每次查询给出l,r
求(l,l+1,l+2…r-1,r)这段区间不考虑哪个节点之后能让剩余节点的lca深度尽量大
做法
这道题有好多种做法,我在做的过程中用了三种做法
首先我们要知道,不考虑一个节点能让一些点的lca发生变化的话,
这个点一定是dfs序最小的点或者dfs序最大的点。
如果能想到这个结论第一种做法就很好想
第一种做法
线段树维护区间lca,st表维护区间dfs序,这样给定一段区间之后
我们就可以通过st表找到哪两个点是dfs最小和最大的点
之后线段树上求该点左侧的区间和该点右侧的区间的lca
对dfs序最小的点求一次,对dfs序最大的点求一次,再取个max就是答案
之后的做法需要知道(猜)另一个结论
一些点的lca就是dfs序最小的点和dfs序最大的点的lca
第二种做法
这样我们用线段树维护区间dfs序,
去掉dfs序最小的点之后在剩下的两个区间查找新的dfs序最小/最大的点
求他们的lca,去掉dfs序最大的点再来一遍,取个max就是答案
第三种做法
第三种做法就是基于第二种做法的基础上,我们直接维护区间最大此大最小次小,这样就可以直接查询当前l,r之内的最大最小最小次小dfs序
删除dfs序最大的点,也就是次大dfs序的点与最小dfs序的点求lca
删除dfs序最小的点,也就是次小dfs序的点与最大dfs序的点求lca
两个取个max即可
代码
第一种做法
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
#define dbg(x) cout<<#x<<" = "<<x<<endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
const int maxn = 1e5+10;
vector<int> G[maxn];
int deep[maxn];
int f[maxn][20];
int in[maxn],mp[maxn],time;
void dfs(int u,int fa)
{
f[u][0]=fa;
in[u]=++time;
mp[time]=u;
for(int i=1; i<=19; i++)
f[u][i]=f[f[u][i-1]][i-1];
for(int i=0; i<G[u].size(); i++)
{
int v=G[u][i];
if(v==fa)
continue;
deep[v]=deep[u]+1;
dfs(v,u);
}
}
int lca(int x,int y)
{
if(x==-1) return y;
if(y==-1) return x;
if(deep[x]<deep[y]) swap(x,y);
for (int i=19; i>=0; i--)
{
if(deep[x]-(1LL<<i)>=deep[y]) x=f[x][i];
}
if(x==y) return x;
for(int i=19; i>=0; i--)
if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
struct T
{
int l,r,mid;
int LCA;
} Tree[maxn<<2];
void push_up(int rt)
{
Tree[rt].LCA=lca(Tree[rt<<1].LCA,Tree[rt<<1|1].LCA);
}
void build(int rt,int l,int r)
{
Tree[rt].l=l;
Tree[rt].r=r;
Tree[rt].LCA=-1;
if(l==r)
{
Tree[rt].LCA=l;
return ;
}
int mid=Tree[rt].mid=l+r>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
push_up(rt);
}
int query(int rt,int l,int r)
{
if(l>r) return -1;
if(Tree[rt].l>=l&&Tree[rt].r<=r) return Tree[rt].LCA;
if(Tree[rt].l>r||Tree[rt].r<l) return -1;
int ans=-1;
if(l<=Tree[rt].mid) ans=query(rt<<1,l,r);
if(r>Tree[rt].mid) ans=lca(ans,query(rt<<1|1,l,r));
return ans;
}
inline int min_(int x,int y)
{
return x<y?x:y;
}
inline int max_(int x,int y)
{
return x>y?x:y;
}
int f2[maxn][16],f3[maxn][16];
void build_st(int n)
{
int p=0;
for(int i=1; i<=n; i<<=1) p++;
for(int i=1; i<=n; i++)
{
f2[i][0]=in[i];
f3[i][0]=in[i];
}
for(int j=1; j<p; j++)
{
for(int i=1; i<=n; i++)
{
if(i+(1<<j-1)>n)
f2[i][j]=f2[i][j-1];
else
f2[i][j]=max_(f2[i][j-1],f2[i+(1<<j-1)][j-1]);
}
}
for(int j=1; j<p; j++)
{
for(int i=1; i<=n; i++)
{
if(i+(1<<j-1)>n) f3[i][j]=f3[i][j-1];
else f3[i][j]=min_(f3[i][j-1],f3[i+(1<<j-1)][j-1]);
}
}
}
int query_max(int l,int r)
{
int p=log2(r-l+1);
return max_(f2[l][p],f2[r-(1<<p)+1][p]);
}
int query_min(int l,int r)
{
int p=log2(r-l+1);
return min_(f3[l][p],f3[r-(1<<p)+1][p]);
}
int main()
{
int n,q,x,y;
scanf("%d%d",&n,&q);
for(int i=2; i<=n; i++)
{
scanf("%d",&x);
G[x].push_back(i);
G[i].push_back(x);
}
dfs(1,0);// deep ok lca ok dfsxu ok
build_st(n);
build(1,1,n);
while(q--)
{
scanf("%d%d",&x,&y);
int st=mp[query_min(x,y)];
int en=mp[query_max(x,y)];
int ans1=lca(query(1,x,st-1),query(1,st+1,y));
int ans2=lca(query(1,x,en-1),query(1,en+1,y));
if(deep[ans1]>deep[ans2]) printf("%d %d\n",st,max_(deep[ans1],deep[ans2]));
else printf("%d %d\n",en,max_(deep[ans1],deep[ans2]));
}
return 0;
}
第二种做法
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
#define dbg(x) cout<<#x<<" = "<<x<<endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
const int maxn = 1e5+10;
vector<int> G[maxn];
int deep[maxn];
int f[maxn][20];
int in[maxn],mp[maxn],time;
void dfs(int u,int fa)
{
f[u][0]=fa;
in[u]=++time;
mp[time]=u;
for(int i=1; i<=19; i++)
f[u][i]=f[f[u][i-1]][i-1];
for(int i=0; i<G[u].size(); i++)
{
int v=G[u][i];
if(v==fa)
continue;
deep[v]=deep[u]+1;
dfs(v,u);
}
}
int lca(int x,int y)
{
if(deep[x]<deep[y]) swap(x,y);
for (int i=19; i>=0; i--)
{
if(deep[x]-(1LL<<i)>=deep[y]) x=f[x][i];
}
if(x==y) return x;
for(int i=19; i>=0; i--)
if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
struct T
{
int l,r,mid;
int maxx,minn;
} Tree[maxn<<2];
void push_up(int rt)
{
Tree[rt].maxx=max(Tree[rt<<1].maxx,Tree[rt<<1|1].maxx);
Tree[rt].minn=min(Tree[rt<<1].minn,Tree[rt<<1|1].minn);
}
void build(int rt,int l,int r)
{
Tree[rt].l=l;
Tree[rt].r=r;
Tree[rt].maxx=-1;
Tree[rt].minn=1000000;
if(l==r)
{
Tree[rt].maxx=in[l];
Tree[rt].minn=in[l];
return ;
}
int mid=Tree[rt].mid=l+r>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
push_up(rt);
}
int ans_max,ans_min;
void query(int rt,int l,int r)
{
if(l>r) return ;
if(Tree[rt].l>r||Tree[rt].r<l) return ;
if(Tree[rt].l>=l&&Tree[rt].r<=r)
{
ans_max=max(ans_max,Tree[rt].maxx);
ans_min=min(ans_min,Tree[rt].minn);
return;
}
if(l<=Tree[rt].mid) query(rt<<1,l,r);
if(r>Tree[rt].mid) query(rt<<1|1,l,r);
return ;
}
int main()
{
int n,q,x,y;
scanf("%d%d",&n,&q);
for(int i=2; i<=n; i++)
{
scanf("%d",&x);
G[x].push_back(i);
G[i].push_back(x);
}
dfs(1,0);
build(1,1,n);
while(q--)
{
scanf("%d%d",&x,&y);
ans_max=0,ans_min=1000000;
query(1,x,y);
int st=mp[ans_max];
int en=mp[ans_min];
ans_max=0,ans_min=1000000;
query(1,x,st-1);query(1,st+1,y);
int ans1=deep[lca(mp[ans_max],mp[ans_min])];
ans_max=0,ans_min=1000000;
query(1,x,en-1);query(1,en+1,y);
int ans2=deep[lca(mp[ans_max],mp[ans_min])];
if(ans1>ans2) printf("%d %d\n",st,ans1);
else printf("%d %d\n",en,ans2);
}
return 0;
}
第三种做法
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
#define dbg(x) cout<<#x<<" = "<<x<<endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
const int maxn = 1e5+10;
vector<int> G[maxn];
int deep[maxn];
int f[maxn][20];
int in[maxn],mp[maxn],time;
void dfs(int u,int fa)
{
f[u][0]=fa;
in[u]=++time;
mp[time]=u;
for(int i=1; i<=19; i++)
f[u][i]=f[f[u][i-1]][i-1];
for(int i=0; i<G[u].size(); i++)
{
int v=G[u][i];
if(v==fa)
continue;
deep[v]=deep[u]+1;
dfs(v,u);
}
}
int lca(int x,int y)
{
if(deep[x]<deep[y]) swap(x,y);
for (int i=19; i>=0; i--)
{
if(deep[x]-(1LL<<i)>=deep[y]) x=f[x][i];
}
if(x==y) return x;
for(int i=19; i>=0; i--)
if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
struct T
{
int l,r,mid;
int maxx[2],minn[2];
} Tree[maxn<<2];
void push_up(int rt)
{
vector<int> t;
t.push_back(Tree[rt<<1].maxx[0]);
t.push_back(Tree[rt<<1].maxx[1]);
t.push_back(Tree[rt<<1|1].maxx[0]);
t.push_back(Tree[rt<<1|1].maxx[1]);
sort(t.begin(),t.end());
Tree[rt].maxx[0]=t[3];
Tree[rt].maxx[1]=t[2];
t.clear();
t.push_back(Tree[rt<<1].minn[0]);
t.push_back(Tree[rt<<1].minn[1]);
t.push_back(Tree[rt<<1|1].minn[0]);
t.push_back(Tree[rt<<1|1].minn[1]);
sort(t.begin(),t.end());
Tree[rt].minn[0]=t[0];
Tree[rt].minn[1]=t[1];
}
void build(int rt,int l,int r)
{
Tree[rt].l=l;
Tree[rt].r=r;
Tree[rt].maxx[0]=-1;
Tree[rt].maxx[1]=-1;
Tree[rt].minn[0]=1000000;
Tree[rt].minn[1]=1000000;
if(l==r)
{
Tree[rt].maxx[0]=in[l];
Tree[rt].minn[0]=in[l];
return ;
}
int mid=Tree[rt].mid=l+r>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
push_up(rt);
}
vector<int> maxx,minn;
bool cmp(int a,int b)
{
return a>b;
}
void query(int rt,int l,int r)
{
if(l>r) return ;
if(Tree[rt].l>r||Tree[rt].r<l) return ;
if(Tree[rt].l>=l&&Tree[rt].r<=r)
{
maxx.push_back(Tree[rt].maxx[0]);
maxx.push_back(Tree[rt].maxx[1]);
minn.push_back(Tree[rt].minn[0]);
minn.push_back(Tree[rt].minn[1]);
return;
}
if(l<=Tree[rt].mid) query(rt<<1,l,r);
if(r>Tree[rt].mid) query(rt<<1|1,l,r);
return ;
}
int main()
{
int n,q,x,y;
scanf("%d%d",&n,&q);
for(int i=2; i<=n; i++)
{
scanf("%d",&x);
G[x].push_back(i);
G[i].push_back(x);
}
dfs(1,0);
build(1,1,n);
while(q--)
{
scanf("%d%d",&x,&y);
maxx.clear();
minn.clear();
query(1,x,y);
sort(maxx.begin(),maxx.end(),cmp);
sort(minn.begin(),minn.end());
int ans1=deep[lca(mp[maxx[0]],mp[minn[1]])];
int ans2=deep[lca(mp[maxx[1]],mp[minn[0]])];
if(ans1>ans2) printf("%d %d\n",mp[minn[0]],ans1);
else printf("%d %d\n",mp[maxx[0]],ans2);
}
return 0;
}
F. Upgrading Cities
题意
给你一个n个点m条边的DAG(有向无环图),问有多少个点的可到达的点数+可以被到达的点数>=n-1
做法
由于是有向无环图,我们首先考虑拓扑排序,如果A能够到达B,那么A,B肯定不会同时出现在队列中,所以如果队列中同时存在的点超过两个,这些点肯定都是不能互相到达的,也就是说对答案肯定没有贡献,之后考虑如果队列中只有一个点,那么所有没进队的点肯定都能到达,之后考虑如果队列中恰好有两个点,设两个点分别为A,B,B有一条边指向一个入度为1的点C,那么A肯定不能到达C,所以A到达不了A,B,也就是A不能对答案做贡献,如果没有这种情况,A可以到所有剩下没有进入队列的点。这是处理一个点能到哪些点的情况,对于被哪些点到达的情况,只需要反向建边再跑一边这个过程即可。两遍topo排序之后,看哪些点满足条件即可。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 3e5+5;
vector<int> G[2][maxn];
int ind[2][maxn],que[maxn],n,m;
int sum[maxn];
void topsort(int pos)
{
int qt = 0;
for(int i = 1; i <= n; ++i)
{
if(ind[pos][i] == 0) que[qt++] = i;
}
for(int i = 0; i < qt; ++i)
{
int u = que[i];
if(qt-i==1)
{
sum[u]+=n-qt;
}
else if(qt-i==2)
{
int u_2=que[i+1];
int flag=0;
for(int j=0;j<G[pos][u_2].size();++j) if(ind[pos][G[pos][u_2][j]]==1) flag=1;
if(flag==0) sum[u]+=(n-qt);
}
for(int j=0;j<G[pos][u].size();++j) if(--ind[pos][G[pos][u][j]] == 0) que[qt++] = G[pos][u][j];
}
return ;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
G[0][u].push_back(v);
ind[0][v]++;
G[1][v].push_back(u);
ind[1][u]++;
}
topsort(0);
topsort(1);
int ans=0;
for(int i=1;i<=n;i++) if(sum[i]>=n-2) ++ans;
printf("%d\n",ans);
return 0;
}