Jeff and Removing Periods
因为删除后可以任意排序,所以除第一次删除,每次都可以删去一种颜色,统计区间中有多少种颜色,可以使用莫队维护。对于第一次操作,如果其不能删去一种颜色,则操作次数加一,反之不变。因此我们问题变为了判断区间中是否存在颜色,使得这些颜色对应的位置形成等差数列。
这个也可以在莫队加点或删点时维护。令 \(dis_i\) 表示位置 \(i\) 到上一个颜色与 \(a_i\) 相同的点 \(x\) 的距离,如果 \(i\) 可以接在 \(x\) 的后面和它在一个等差数列中,则 \(dis_i=dis_x\)。用并查集维护这种在一个等差数列中的数,再用双端队列维护在区间中的颜色为 \(a_i\) 的数,最后只要判断队列大小是否为 \(1\),或者队列中的第 \(2\) 个数和最后一个数是否在一个并查集中就可以判断是否存在一个颜色的数的位置构成一个等差数列了。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=1e5+10;
int n,Q,B,a[N],pos[N],dis[N],fa[N],cnt,ans[N],sum[N],tot;
struct query{
int l,r,id;
}que[N];
bool cmp(query x,query y){
if(x.l/B==y.l/B){
return x.r<y.r;
}
return x.l<y.l;
}
int getfa(int x){
if(fa[x]!=x){
fa[x]=getfa(fa[x]);
}
return fa[x];
}
deque<int>q[N];
bool check(int x){
if(!q[x].size()){
return 0;
}
if(q[x].size()==1){
return 1;
}
int first=q[x].front(),flag=0;
q[x].pop_front();
if(getfa(q[x].front())==getfa(q[x].back())){
flag=1;
}
q[x].push_front(first);
return flag;
}
void add(int id,int type){
if(check(a[id])){
tot--;
}
sum[a[id]]++;
if(sum[a[id]]==1){
cnt++;
}
if(type){
q[a[id]].push_back(id);
}
else{
q[a[id]].push_front(id);
}
if(check(a[id])){
tot++;
}
}
void del(int id,int type){
if(check(a[id])){
tot--;
}
if(sum[a[id]]==1){
cnt--;
}
sum[a[id]]--;
if(type){
q[a[id]].pop_back();
}
else{
q[a[id]].pop_front();
}
if(check(a[id])){
tot++;
}
}
void solve(){
read(n);
for(int i=1;i<=n;i++){
read(a[i]);
if(!pos[a[i]]){
fa[i]=i;
dis[i]=0;
}
else{
if(i-pos[a[i]]==dis[pos[a[i]]]){
fa[i]=pos[a[i]];
}
else{
fa[i]=i;
}
dis[i]=i-pos[a[i]];
}
pos[a[i]]=i;
}
read(Q);
B=sqrt(Q);
for(int i=1;i<=Q;i++){
read(que[i].l),read(que[i].r);
que[i].id=i;
}
sort(que+1,que+Q+1,cmp);
int l=1,r=0;
for(int i=1;i<=Q;i++){
while(l>que[i].l){
add(--l,0);
}
while(r<que[i].r){
add(++r,1);
}
while(l<que[i].l){
del(l++,0);
}
while(r>que[i].r){
del(r--,1);
}
ans[que[i].id]=cnt+(tot==0);
}
for(int i=1;i<=Q;i++){
write_endl(ans[i]);
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}
[CERC2016] 二分毯 Bipartite Blanket
需要注意的是题目求的是 \(V\subseteq S\text{(S表示一个匹配的点集)}\),而不是 \(V=S\)。可以发现该题意中左右两侧是无关的,只要左右两边分别能在匹配中,两个点集的并就能在匹配中,具体证明详见zltqwq的P3679题解。
这样,我们可以分开求一个左边的点集和右边的点集是否在一个匹配中。根据hall定理,对于一个左部图大小为 \(X\)、右部图大小为 \(Y\) 的二分图,如果存在左侧点的完美匹配,则对于任意一个左侧点的子集 \(S\),所有与该子集中的点相邻的点所构成的集合大小必须大于等于该子集的大小。自行使用高维前缀和维护,再用一遍双指针维护两边子集的权值和大于等于 \(t\) 的方案数。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pdi pair<double,int>
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define eps 1e-9
using namespace std;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=50,M=1<<21;
int n,m,val[2][N],e[N][N],mn,couple[N],vis[N],s[M],t[M],ansl[M],ansr[M];
vector<int>suma,sumb;
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
read(n),read(m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char opt=getchar();
while(opt!='0'&&opt!='1'){
opt=getchar();
}
e[i][j]=opt-'0';
if(e[i][j]){
s[1<<(i-1)]|=(1<<(j-1));
t[1<<(j-1)]|=(1<<(i-1));
}
}
}
for(int i=1;i<=n;i++){
read(val[0][i]);
}
for(int i=1;i<=m;i++){
read(val[1][i]);
}
read(mn);
suma.pb(0),sumb.pb(0);
ll p=0,ans=0;
for(int k=1;k<(1<<n);k*=2){
for(int i=0;i<(1<<n);i+=k*2){
for(int j=i;j<i+k;j++){
s[j+k]|=s[j];
}
}
}
for(int k=1;k<(1<<m);k*=2){
for(int i=0;i<(1<<m);i+=k*2){
for(int j=i;j<i+k;j++){
t[j+k]|=t[j];
}
}
}
ansl[0]=ansr[0]=1;
for(int i=1;i<(1<<n);i++){
if(__builtin_popcount(i)<=__builtin_popcount(s[i])){
ansl[i]=1;
}
}
for(int i=1;i<(1<<m);i++){
if(__builtin_popcount(i)<=__builtin_popcount(t[i])){
ansr[i]=1;
}
}
for(int k=1;k<(1<<n);k*=2){
for(int i=0;i<(1<<n);i+=k*2){
for(int j=i;j<i+k;j++){
ansl[j+k]&=ansl[j];
}
}
}
for(int k=1;k<(1<<m);k*=2){
for(int i=0;i<(1<<m);i+=k*2){
for(int j=i;j<i+k;j++){
ansr[j+k]&=ansr[j];
}
}
}
for(int i=1;i<(1<<n);i++){
if(ansl[i]){
int sum=0;
for(int j=1;j<=n;j++){
if(i>>(j-1)&1){
sum+=val[0][j];
}
}
suma.pb(sum);
}
}
for(int i=1;i<(1<<m);i++){
if(ansr[i]){
int sum=0;
for(int j=1;j<=m;j++){
if(i>>(j-1)&1){
sum+=val[1][j];
}
}
sumb.pb(sum);
}
}
sort(suma.begin(),suma.end());
sort(sumb.begin(),sumb.end());
for(int i=suma.size()-1;i>=0;i--){
while(p<sumb.size()&&suma[i]+sumb[p]<mn){
p++;
}
ans+=(sumb.size()-p);
}
write_endl(ans);
// cerr<<1.0*clock()/CLOCKS_PER_SEC<<endl;
return 0;
}
Nezzar and Hidden Permutations
洛谷翻译太难绷了,写个题意。
题意:给定一张无向图,要求构造两个排列 \(a,b\),使得对于任意一条边 \((u,v)\) 都满足 \((a_u-a_v)(b_u-b_v)>0\),在这个要求下,使得 \(a_u=b_u\) 的数量最少。
假定当前有 \(n\) 个点,如果存在一个点 \(x\) 连了 \(n-1\) 条边,此时该点 \(a_x=b_x\)。为了方便,令 \(a_x=b_x=n\)。删去该点后继续进行上述操作,直到不存在这样的点 \(x\)。此时对于剩下的任意一个点 \(u\),都存在 \(deg_u\le n-2\)。因为这个限制不好做,考虑求剩下的图的补图,对于补图上的一条边,可以构造 \((x,x+1),(x+1,x)\),对于一条没处理的边,相当于加了一个限制,条件更加严格。但是这样会出现很多单点,这些单点显然只能填 \(x,x\) 不满足 \(a_u=b_u\) 的数量最少,最典型的情况是菊花图,会造出 \(n-2\) 个 \(a_i=b_i\) 的点。但是其实菊花图我们是有处理的方法的,令大小为 \(n\),将根赋为 \((1,n)\),将第 \(i\) 个叶子赋为 \((i+1,i)\),对于整个菊花是一定满足条件,且能够得到 \(0\) 个 \(a_u=b_u\) 的点。
上述提醒了我们可以将一个图求出生成树后,将其拆成若干个菊花图,对于每个菊花图做一遍上述做法,并令菊花图与菊花图之间满足限制,将一段区间的值赋给一个菊花图。求生成树也很简单,直接求dfs树即可。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=5e5+10;
int n,m,deg[N],a[N],b[N],siz[N],rt[N],col[N],col_cnt,vis[N];
vector<int>e[N],v_col[N];
set<int>S,G[N];
queue<int>q;
void init(){
col_cnt=0;
for(int i=1;i<=n;i++){
vis[i]=deg[i]=col[i]=siz[i]=a[i]=b[i]=0;
vector<int>().swap(e[i]);
vector<int>().swap(v_col[i]);
set<int>().swap(G[i]);
S.insert(i);
}
}
void build(int u,int fa){
for(auto v:S){
if(!G[u].count(v)){
e[u].pb(v);
e[v].pb(u);
}
}
for(auto v:e[u]){
if(v==fa){
continue;
}
S.erase(v);
}
for(auto v:e[u]){
if(v==fa){
continue;
}
build(v,u);
}
}
void dfs(int u,int fa){
bool f=0;
if(!col[u]){
for(auto v:e[u]){
if(!col[v]){
f=1;
}
}
if(f){
col[u]=++col_cnt;
rt[col_cnt]=u;
siz[col_cnt]=1;
for(auto v:e[u]){
if(!col[v]){
++siz[col_cnt];
col[v]=col_cnt;
}
}
}
else{
for(auto v:e[u]){
if(col[v]){
if(rt[col[v]]==v){
++siz[col[v]];
col[u]=col[v];
}
else if(siz[col[v]]>2){
col[u]=++col_cnt;
rt[col_cnt]=u;
siz[col_cnt]=2;
--siz[col[v]];
col[v]=col_cnt;
}
else{
rt[col[v]]=v;
++siz[col[v]];
col[u]=col[v];
}
break;
}
}
}
}
for(auto v:e[u]){
if(v==fa){
continue;
}
dfs(v,u);
}
}
void solve(){
read(n),read(m);
int tot=n;
init();
for(int i=1;i<=m;i++){
int u,v;
read(u),read(v);
G[u].insert(v);
G[v].insert(u);
deg[u]++;
deg[v]++;
}
for(int i=1;i<=n;i++){
if(deg[i]==n-1){
S.erase(i);
q.push(i);
}
}
while(q.size()){
int u=q.front();
q.pop();
a[u]=b[u]=tot--;
vis[u]=1;
for(auto v:e[u]){
--deg[v];
if(S.count(v)&°[v]==tot-1){
q.push(v);
S.erase(v);
}
}
}
for(int i=1;i<=n;i++){
if(S.count(i)){
S.erase(i);
build(i,0);
}
}
for(int i=1;i<=n;i++){
if(!a[i]&&!col[i]){
dfs(i,0);
}
}
for(int i=1;i<=n;i++){
if(col[i]){
v_col[col[i]].pb(i);
}
}
for(int i=1,s=1;i<=col_cnt;i++,s++){
b[rt[i]]=s;
for(auto u:v_col[i]){
if(u!=rt[i]){
a[u]=s;
b[u]=++s;
}
}
a[rt[i]]=s;
}
for(int i=1;i<=n;i++){
write_space(a[i]);
}
putchar('\n');
for(int i=1;i<=n;i++){
write_space(b[i]);
}
putchar('\n');
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t;
read(t);
while(t--){
solve();
}
return 0;
}
[POI2006] MET-Subway
看题目容易让人想到最小路径覆盖问题,但是这个问题的全局最优显然和局部最优的策略是不同的。
贪心地考虑,本题的每条路径一定是从叶子到叶子,因为若存在路径的端点不是叶子,扩展到叶子一定能在路径数不增多的情况下,答案更大。同理,在选定某个点为根时,我们一定会优先选贡献更多的点,因此我们令一个点的阶数为该点到叶子的最远距离。因此如果能选一个 \(x\) 阶点,必然能选到对应的 \(0\sim x-1\) 阶点。因此对于一个高阶点,显然是能选就选,对于一个 \(i\) 阶点,令 \(cnt_i\) 表示 \(i\) 阶点的数量,则能选的数量的最大值为 \(\min(k\times 2,cnt_i)\)。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=1e6+10;
int n,cnt,deg[N],dep[N],tot[N];
vector<int>e[N];
void solve(){
read(n),read(cnt);
for(int i=1;i<n;i++){
int u,v;
read(u),read(v);
e[u].pb(v);
e[v].pb(u);
deg[u]++;
deg[v]++;
}
queue<int>q;
for(int i=1;i<=n;i++){
if(deg[i]==1){
q.push(i);
tot[0]++;
}
}
while(q.size()){
int u=q.front();
q.pop();
for(auto v:e[u]){
deg[v]--;
if(deg[v]==1){
dep[v]=dep[u]+1;
tot[dep[v]]++;
q.push(v);
}
}
}
int ans=0;
for(int i=0;i<=n;i++){
ans+=min(cnt*2,tot[i]);
}
write_endl(ans);
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}
Garden of the Sun
一开始有个想法是两行为一组,但如果这两行上都没有关键点,就很难处理,于是考虑三行一组。此时我们可以将每一组的第一行全染,因为任意两个关键点都没有交点或交边,所以这样是不会出现两组之间有两个竖着的直接穿过,形成环。上面两行一组就不能这么做,因为中间的一行只要存在两个及以上的关键点就一定会形成环。
接下来只要维护连通性即可,对于第 \(i\) 组和第 \(i+1\) 组($i<\lfloor\frac{n}{3}\rfloor$)之间的部分,如果第 \(i\) 组 \(2\) 列有关键点,则将第 \(2\) 列的两个点都染色,否则染第一列的两个点。可行性很显然,因为若第 \(2\) 列有关键点,则第 \(1,3\) 列肯定没有关键点,不会形成 \(4\) 格环;若第 \(2\) 列没有关键点,则第 \(1\) 列连上肯定不会和第 \(2\) 列的点产生 \(4\) 格环。需要注意的是如果最后一组也有 \(3\) 行,需要将最后一行的点连通到上面的连通块中,特判一下即可。
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=510;
int n,m,a[N][N];
void solve(){
read(n),read(m);
for(int i=1;i<=n+1;i++){
for(int j=1;j<=m+1;j++){
a[i][j]=0;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char opt=getchar();
while(opt!='.'&&opt!='X'){
opt=getchar();
}
if(opt=='.'){
a[i][j]=0;
}
else{
a[i][j]=1;
}
}
}
for(int i=1;i<=n;i+=3){
for(int j=1;j<=m;j++){
a[i][j]=1;
}
}
for(int i=2;i<=n;i+=3){
if(a[i][2]||a[i+1][2]){
a[i][2]=a[i+1][2]=1;
}
else{
a[i][1]=a[i+1][1]=1;
}
}
if(n%3==0){
for(int i=1;i<=m;i++){
if(a[n][i]||a[n-1][i]){
a[n][i]=a[n-1][i]=1;
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]){
putchar('X');
}
else{
putchar('.');
}
}
putchar('\n');
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t;
read(t);
while(t--){
solve();
}
return 0;
}
BFS Trees
首先注意到如果两个点的 bfs 树是相同的,两个点 \(x,y\) 之间的最短路的路径一定只有一条。如果存在多条,则 \(x\) 的 bfs 树中会删掉若干条与 \(y\) 相连的边,但这些边是一定在 \(y\) 的 bfs 树中的,同理 \(y\) 的 bfs 树中也一定会删掉若干条一定在 \(x\) 的 bfs 树中的边。
再考虑一条边 \((u,v)\) 可能在 bfs 树中要满足什么条件,令 bfs 树的根为 \(rt\),\(d_{i,j}\) 表示 \(i\) 到 \(j\) 的最短路的长度,则 \(d_{rt,u}+1=d_{rt,v}\),同理对于同时在两棵 bfs 树中,则对于两棵树都要满足上述条件,对于所有的不在最短路上的点 \(v\),找到这样的边 \((u,v)\) 的数量,答案为乘积,复杂度 \(O(n^2m)\)
点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
template<typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+(ch-'0');
ch=getchar();
}
x=(f==1?x:-x);
}
template<typename T>
inline void write(T x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10){
write(x/10);
}
putchar(x%10+'0');
}
template<typename T>
inline void write_endl(T x){
write(x);
putchar('\n');
}
template<typename T>
inline void write_space(T x){
write(x);
putchar(' ');
}
}
using namespace IO;
const int N=410,mod=998244353;
int n,m,d[N][N],cnt[N][N];
vector<int>e[N];
void bfs(int st){
queue<int>q;
q.push(st);
for(int i=1;i<=n;i++){
d[st][i]=inf;
}
d[st][st]=0;
cnt[st][st]=1;
while(q.size()){
int u=q.front();
q.pop();
for(auto v:e[u]){
if(d[st][v]>d[st][u]+1){
d[st][v]=d[st][u]+1;
cnt[st][v]=cnt[st][u];
q.push(v);
}
else if(d[st][v]==d[st][u]+1){
cnt[st][v]+=cnt[st][u];
}
}
}
}
void solve(){
read(n),read(m);
for(int i=1;i<=m;i++){
int u,v;
read(u),read(v);
e[u].pb(v);
e[v].pb(u);
}
for(int i=1;i<=n;i++){
bfs(i);
}
// for(int i=1;i<=n;i++){
// for(int j=1;j<=n;j++){
// cerr<<cnt[i][j]<<' ';
// }
// cerr<<endl;
// }
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(cnt[i][j]>1){
write_space(0);
continue;
}
int ans=1;
for(int k=1;k<=n;k++){
if(d[i][k]+d[k][j]==d[i][j]){
continue;
}
int cnt=0;
for(auto v:e[k]){
if(d[i][v]+1==d[i][k]&&d[j][v]+1==d[j][k]){
cnt++;
}
}
ans=1ll*ans*cnt%mod;
}
write_space(ans);
}
putchar('\n');
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int t=1;
while(t--){
solve();
}
return 0;
}