Day 1
T1 卡牌游戏
由于现在还没有官方数据,所以这是我考场上的思路,能通过随机数据,但不保证正确,欢迎大家来hack:
首先,容易发现最终答案一定会翻一段前缀 (1sim l) 和一段后缀 (rsim n),且如果将 (a[l+1]) 也算入前缀中,那么最小值一定会在前缀或后缀中。
我们首先钦定最小值在前缀中,枚举 (l),此时我们从后往前依次翻牌,尽量降低最大值,那么显然一旦在某一时刻后缀 (b[rsim n]) 的最大值大于 (a[r]) 了,那么就不应该再翻 (r) 了,同时如果后缀最小值小于前缀最小值,我们也停止翻牌,这个临界点是容易二分出来的,当然双指针也是可以的。
接下来钦定最小值在后缀中,枚举 (r),那么此时我们一定要求 (a[l+1]gemin_{i=r}^{n}b[i]),同时对于所有符合这一条件的 (l),如果增加 (l) ,前缀最小值会减小导致可能无法满足钦定的条件,最大值都会增加导致答案增加,因此一定不优,我们只需要检验最小的符合条件的 (l) 即可,这是容易双指针/二分找出的。
upd:官方数据过了,uoj三十多组hack也过了
博主的憨批二分代码>
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,m,a[N],b[N];
int pmn[N],pmx[N],smn[N],smx[N];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=n;++i) scanf("%d",&b[i]);
pmn[0]=smn[n+1]=a[n+1]=0x3f3f3f3f;
pmx[0]=smx[n+1]=-0x3f3f3f3f;
for(int i=1;i<=n;++i) pmn[i]=min(pmn[i-1],b[i]),pmx[i]=max(pmx[i-1],b[i]);
for(int i=n;i>=1;--i) smn[i]=min(smn[i+1],b[i]),smx[i]=max(smx[i+1],b[i]);
int ret=a[n]-a[1];
for(int i=0;i<=m;++i){
int l=i+n+1-m,r=n+1,ans=0,mn=min(pmn[i],a[i+1]);
while(l<=r){
int mid=(l+r)>>1;
if(smn[mid]<mn||smx[mid]>a[mid]) l=mid+1;
else r=mid-1,ans=mid;
}
ret=min(ret,max(pmx[i],max(a[ans-1],smx[ans]))-mn);
}
for(int i=n+1;n-i+1<=m;--i){
int l=0,r=m-n+i-1,mn=min(smn[i],a[i-1]),mx=max(smx[i],a[i-1]);
int y=upper_bound(a,a+n+2,mn)-a-1;
if(y<=r&&pmn[y]>=mn) ret=min(ret,max(mx,pmx[y])-mn);
}
printf("%d
",ret);
return 0;
}
T2 矩阵游戏
首先考虑没有 (0le a_{i,j}le 10^6) 这一限制的情况,此时很容易构造一种合法情况:将第一行和第一列随机钦定一些值(博主全赋了 (0)),然后从左到右从上到下依次得到这个矩阵。
现在考虑通过一些调整来得到合法的矩阵,给出两种操作:
1.对于矩阵的一行,依次进行(+1,-1,+1,-1,dots)的操作,显然这样做不会影响其对应的(b)矩阵。
2.对于矩阵的一列,作类似的操作。
引理:通过这两种操作,我们一定能得到所有可以达到的合法状态。
证明
通过一系列列操作修改第一行,再用第(2sim n)行的行操作进行修改,一定能将第一行与第一列变成任何想要的情况。
而原问题相当于有((n-1)(m-1))个方程,要解出(nm)个变量,那么还剩下(n+m-1)个可变量,上面的操作就等于是遍历了这些可变量的所有取值。
现在假设第(i)行进行了 (c_i) 次行操作,第 (j) 列进行了 (d_j) 次列操作,那么新的矩阵的每一位就变成了 (0le pm c_i pm d_j+a_{i,j}le 10^6),注意这里的 (pm) 并不代表遍历所有情况,而仅代表每个 (a_{i,j}) 对应的符号。但是这样的不等式很像我们熟悉的差分约束,但是有的地方是和分约束,难以处理。
考虑将偶数行的 (c) 取反,奇数行的 (d) 取反,那么原矩阵就变成了:
于是我们就可以愉快的使用差分约束求解了,复杂度 (mathcal O(nm(n+m))),由于(SPFA)卡不满,可以通过此题。
view code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1010;
const int MX=1e6;
int b[N][N];
int n,m,T,vis[N],ct[N],first[N],cnt;
ll dis[N],a[N][N];
struct node{
int v,nxt;
ll w;
}e[N*N];
inline void add(int u,int v,ll w){
e[++cnt].v=v;e[cnt].w=w;e[cnt].nxt=first[u];first[u]=cnt;
}
namespace iobuff{
const int LEN=1000000;
char in[LEN+5],out[LEN+5];
char *pin=in,*pout=out,*ed=in,*eout=out+LEN;
inline char gc(void){
#ifdef LOCAL
return getchar();
#endif
return pin==ed&&(ed=(pin=in)+fread(in,1,LEN,stdin),ed==in)?EOF:*pin++;
}
inline void pc(char c){
pout==eout&&(fwrite(out,1,LEN,stdout),pout=out);
(*pout++)=c;
}
inline void flush(){fwrite(out,1,pout-out,stdout),pout=out;}
template<typename T> inline void read(T &x){
static int f;
static char c;
c=gc(),f=1,x=0;
while(c<'0'||c>'9') f=(c=='-'?-1:1),c=gc();
while(c>='0'&&c<='9') x=10*x+c-'0',c=gc();
x*=f;
}
template<typename T> inline void putint(T x,char div){
static char s[15];
static int top;
top=0;
x<0?pc('-'),x=-x:0;
while(x) s[top++]=x%10,x/=10;
!top?pc('0'),0:0;
while(top--) pc(s[top]+'0');
pc(div);
}
}
using namespace iobuff;
inline bool SPFA(){
deque<int> q;
for(int i=1;i<=n+m;++i) q.push_front(i),dis[i]=0;
memset(vis+1,0,sizeof(int)*(n+m));
memset(ct+1,0,sizeof(int)*(n+m));
while(!q.empty()){
int u=q.front();
q.pop_front();vis[u]=0;
for(int i=first[u];i;i=e[i].nxt){
int v=e[i].v;
if(dis[u]+e[i].w<dis[v]){
dis[v]=dis[u]+e[i].w;
if(!vis[v]){
vis[v]=1;
if(e[i].w<0) q.push_front(v);
else q.push_back(v);
if((++ct[v])>=n+m) return false;
}
}
}
}
return true;
}
inline void init(){
for(int i=1;i<n;++i)
for(int j=1;j<m;++j)
a[i+1][j+1]=b[i][j]-a[i][j]-a[i+1][j]-a[i][j+1];
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
int l=-a[i][j],r=MX-a[i][j];
if((i+j)%2==0){
add(j+n,i,r);
add(i,j+n,-l);
}
else{
add(i,j+n,r);
add(j+n,i,-l);
}
}
}
}
int main(){
// freopen("mat.in","r",stdin);
read(T);
while(T--){
read(n);read(m);
for(int i=1;i<n;++i)
for(int j=1;j<m;++j)
read(b[i][j]);
for(int i=1;i<=n;++i) a[1][i]=0;
for(int i=1;i<=m;++i) a[i][1]=0;
init();
if(!SPFA()) pc('N'),pc('O'),pc('
');
else{
pc('Y');pc('E');pc('S');pc('
');
for(int i=1;i<=n;++i){
ll x=dis[i];
if(i%2==0) x=-x;ll now=x;
for(int j=1;j<=m;++j,now=-now) a[i][j]+=now;
}
for(int i=1;i<=m;++i){
ll x=dis[i+n];
if(i&1) x=-x;ll now=x;
for(int j=1;j<=n;++j,now=-now) a[j][i]+=now;
}
for(int i=1;i<=n;pc('
'),++i)
for(int j=1;j<=m;++j) putint(a[i][j],' ');
}
memset(first,0,sizeof(int)*(n+m+2));cnt=0;
}
flush();
return 0;
}
T3 图函数
考虑 (h(G)) 中,(u,v) 能作出贡献当且仅当存在两条路径(u ightarrow v)以及(v ightarrow u),满足路径上不经过编号(<v)的点。
于是我们不需要考虑每一张图,考虑每一个点对 ((u,v)) 能作出贡献的一定满足所有合法路径 (u ightarrow v,v ightarrow u)上经过的边的编号最小值依然存在,因此可以求出每一组点对的编号最小值,进而求出答案的差分数组,后缀和得出答案。
如何求出编号最小值?,这是一个 (floyd) 的模型,我们只需要在正图反图上都从大到小遍历所有节点作为中间点,只考虑向 (>) 中间点编号的点转移,复杂度为 (mathcal O(n^3+m)),但是它带有 (2) 倍的常数,因此难以通过。
事实上,我们可以一遍 (floyd) 完成两件事,定义 (f[i][j]),当 (i>j) 是表示从 (i) 出发到 (j),满足路上所有的点编号 (>j) 时边编号的最小值,当 (ile j) 时表示从 (i) 出发到 (j),满足路上所有的点编号 (>i) 时边编号的最小值。然后同样从大到小枚举中间点转移即可。
view code
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,m;
int f[1010][1010],g[1010][1010],ret[N];
inline void floyd(){
for(int k=n;k>=1;--k){
for(int i=k+1;i<=n;++i) ret[min(f[i][k],f[k][i])]++;
for(int i=1;i<=n;++i){
if(f[i][k]){
if(i>k){
int now=f[i][k];
for(int j=1;j<k;++j)
f[i][j]=max(f[i][j],min(now,f[k][j]));
}
else{
int now=f[i][k];
for(int j=1;j<=n;++j)
f[i][j]=max(f[i][j],min(now,f[k][j]));
}
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1,u,v;i<=m;++i){
scanf("%d%d",&u,&v);
f[u][v]=i;
}
floyd();
for(int i=m;i>=1;--i) ret[i]+=ret[i+1];
for(int i=0;i<=m;++i)
printf("%d ",ret[i+1]+n);
return 0;
}
Day 2
T1 宝石
首先将询问 ((u,v)) 拆成 ((u,lca)) 与 ((lca,v)) 两部分。
对于前一部分,我们可以预处理出从每个点向上走时下一类宝石的最近位置,称为其后继,找到该点的$ 2^i$ 级后继,倍增即可。
对于后一部分,考虑二分最终的答案(x),然后找到 (v) 的祖先中最近的(x),然后倍增跳 (x) 的前驱直至到达上行部分的答案处,再检验深度是否超过了 (lca) 即可,前驱的定义与后缀类似,可以用同样的方式预处理。
这一部分需要随时查询 (x) 的最近的颜色为 (w) 的点,我们可以可持久化,也可以将询问离线到 (v) 上,在处理所有询问时,实时更新当前点到祖先链上所有颜色的出现位置,就可以快速查询了。
复杂度为 (mathcal O(nlog^2(n)))
view code
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,m,c,p[N],id[N],cnt;
struct node{
int v,nxt;
}e[N<<1];
int first[N];
inline void add(int u,int v){e[++cnt].v=v;e[cnt].nxt=first[u];first[u]=cnt;}
namespace iobuff{
const int LEN=1000000;
char in[LEN+5],out[LEN+5];
char *pin=in,*pout=out,*ed=in,*eout=out+LEN;
inline char gc(void){
#ifdef LOCAL
return getchar();
#endif
return pin==ed&&(ed=(pin=in)+fread(in,1,LEN,stdin),ed==in)?EOF:*pin++;
}
inline void pc(char c){
pout==eout&&(fwrite(out,1,LEN,stdout),pout=out);
(*pout++)=c;
}
inline void flush(){fwrite(out,1,pout-out,stdout),pout=out;}
template<typename T> inline void read(T &x){
static int f;
static char c;
c=gc(),f=1,x=0;
while(c<'0'||c>'9') f=(c=='-'?-1:1),c=gc();
while(c>='0'&&c<='9') x=10*x+c-'0',c=gc();
x*=f;
}
template<typename T> inline void putint(T x,char div){
static char s[15];
static int top;
top=0;
x<0?pc('-'),x=-x:0;
while(x) s[top++]=x%10,x/=10;
!top?pc('0'),0:0;
while(top--) pc(s[top]+'0');
pc(div);
}
}
using namespace iobuff;
int pa[N][20],fa[N],dep[N],up[N][20],dwn[N][20],col[N],ret[N];
int MX,lim,st[N],w[N];
inline int LCA(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
int t=dep[u]-dep[v];
for(int i=MX;i>=0;--i) if(t&(1<<i)) u=pa[u][i];
if(u==v) return u;
for(int i=MX;i>=0;--i)
if(pa[u][i]!=pa[v][i]) u=pa[u][i],v=pa[v][i];
return pa[u][0];
}
inline void dfs(int u,int f){
fa[u]=f;dep[u]=dep[f]+1;
int rec=col[w[u]];col[w[u]]=u;
up[u][0]=col[w[u]+1];
dwn[u][0]=w[u]==0?0:col[w[u]-1];
pa[u][0]=f;st[u]=col[1];
for(int i=1;(1<<i)<=dep[u];++i)
pa[u][i]=pa[pa[u][i-1]][i-1];
for(int i=1;(1<<i)<=c-w[u]+1;++i) up[u][i]=up[up[u][i-1]][i-1];
for(int i=1;(1<<i)<=w[u];++i) dwn[u][i]=dwn[dwn[u][i-1]][i-1];
for(int i=first[u];i;i=e[i].nxt){
int v=e[i].v;if(v==f) continue;
dfs(v,u);
}
col[w[u]]=rec;
}
inline bool check(int u,int lca,int x,int now){
if(dep[col[x]]<dep[lca]) return false;
u=col[x];
int rem=x-now-1;
for(int i=lim;i>=0;--i){
if(rem&(1<<i)){
if(dep[dwn[u][i]]<dep[lca]) return false;
u=dwn[u][i];
}
}
return true;
}
vector<pair<int,int> > que[N];
inline void solve(int u){
int rec=col[w[u]];col[w[u]]=u;
for(int i=0;i<que[u].size();++i){
int v=que[u][i].first,id=que[u][i].second;
int lca=LCA(u,v),now=0;
if(dep[st[v]]>=dep[lca]){
v=st[v];now=1;
for(int i=lim;i>=0;--i)
if(dep[up[v][i]]>=dep[lca]) v=up[v][i],now+=1<<i;
}
int l=now+1,r=c,ans=now;
while(l<=r){
int mid=(l+r)>>1;
if(check(u,lca,mid,now)) l=mid+1,ans=mid;
else r=mid-1;
}
ret[id]=ans;
}
for(int i=first[u];i;i=e[i].nxt){
int v=e[i].v;if(v==fa[u]) continue;
solve(v);
}
col[w[u]]=rec;
}
int main(){
read(n);read(m);read(c);
MX=log2(n);lim=log2(c);
for(int i=1;i<=c;++i) read(p[i]),id[p[i]]=i;
for(int i=1;i<=n;++i) read(w[i]),w[i]=id[w[i]];
for(int i=1,u,v;i<n;++i){
read(u);read(v);
add(u,v);add(v,u);
}
int q;read(q);
for(int i=1;i<=q;++i){
int u,v;read(u);read(v);
que[v].push_back(make_pair(u,i));
}
dfs(1,0);
solve(1);
for(int i=1;i<=q;++i) putint(ret[i],'
');
flush();
return 0;
}
T2 滚榜
考虑暴力怎么做,暴力是不是,枚举全排列,检验某一个排列时,对于每一支队伍都尽量选择最小的 (b_i) ,看总题数够不够。
考虑一个暴力的 (dp),定义 (dp[s][u][w][m]),表示当前已经公布了 (s) 对应的队伍集合的成绩,上一个公布的队伍为 (u),它的最终分数为 (w),现在还剩下 (m) 道题可以使用。然后暴力枚举每一维信息按照上面的贪心进行转移,复杂度为 (mathcal O(2^nn^2m^2)),貌似比枚举全排列还要慢。
我们发现状态 (w) 是可以优化掉的,它之所以需要它是因为要为下一支队伍提供加分的下限,那么当我们为队伍 (i) 增加 (b_i) 的分数时,直接为所有还未公布队伍的成绩都先增加一个 (b_i),那么公布它们的成绩时就只需要比较 (a) 的大小了,增加 (b_i) 也不用直接加,直接在剩余做题数上减去若干个 (b),默认后面所有队伍的成绩已经加上了 (b) 就可以了。至此,复杂度优化到了 (mathcal O(2^nn^2m)),可以通过此题。
view code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=20;
int n,m,a[N];
ll ans=0,dp[(1<<13)+20][14][510];
int main(){
scanf("%d%d",&n,&m);
int pos=1;
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
if(a[i]>a[pos]) pos=i;
}
dp[0][pos][m]=1;
for(int i=1;i<(1<<n);++i){
int len=0;
for(int j=1;j<=n;++j) if(i&(1<<j-1)) len++;
for(int j=1;j<=n;++j){
if(!(i&(1<<j-1))) continue;
int s=i^((1<<j-1));
for(int k=1;k<=n;++k){
if(!(s&(1<<k-1)))
if(s!=0||k!=pos) continue;
int dis=max(j<=k?a[k]-a[j]:a[k]-a[j]+1,0),p=dis*(n-len+1);
for(int ret=p;ret<=m;++ret) dp[i][j][ret-p]+=dp[s][k][ret];
}
if(i==(1<<n)-1)
for(int k=0;k<=m;++k) ans+=dp[i][j][k];
}
}
printf("%lld
",ans);
return 0;
}
T3 支配
我们首先建出原图的支配树,满足所有支配点 (u) 的点都是 (u) 在支配树上的祖先。(mathcal O(nm)) 的做法是容易的,直接保留枚举每个点,将其断掉后,从 (1) 出发搜索即可,也有更快的 (mathcal O(nlog(n))) 的做法,具体请参见这篇博客,博主的代码使用的也是这种方法。
首先,点 (u) 的受支配集大小一定不会增大,只可能减小,并且减小当且仅当存在一条从 (y) 到 (u) 的路径(设增加的边是(x ightarrow y),(LCA(x,y)=lca))不经过支配树 (lca-u) 链上的某一点 (z),因为此时点 (z) 就不再支配 (u)。
这个结论的限制还是太宽泛了,给出一个更进一步的结论:点 (u) 的受支配集大小减少当且仅当存在一条从 (y) 到 (u) 的路径不经过 (lca) 的祖先节点或其祖先的儿子。
对于这一结论的证明。首先,存在这条路径时,它不会经过 (lca-u) 链上 (lca) 的直接儿子(这是一定存在的),因此必要性得证。
对于充分性,考虑存在一条从 (y) 到 (u) 的路径经过了 (lca) 某个祖先但没有经过 (lca-u) 链上的所有点,那么此时该点到 (u) 的所有点都是必经的,否则不符合支配树的定义。如果经过了某个祖先的儿子,那么一定会必经 (lca-u) 链上 (lca) 的直接儿子,接下来同样必须要经过 (lca-u) 链上的所有点。
于是对于每个询问,(mathcal O(n))标记后直接 (bfs) 即可。
view code
#include<bits/stdc++.h>
using namespace std;
namespace iobuff{
const int LEN=1000000;
char in[LEN+5],out[LEN+5];
char *pin=in,*pout=out,*ed=in,*eout=out+LEN;
inline char gc(void){
#ifdef LOCAL
return getchar();
#endif
return pin==ed&&(ed=(pin=in)+fread(in,1,LEN,stdin),ed==in)?EOF:*pin++;
}
inline void pc(char c){
pout==eout&&(fwrite(out,1,LEN,stdout),pout=out);
(*pout++)=c;
}
inline void flush(){fwrite(out,1,pout-out,stdout),pout=out;}
template<typename T> inline void read(T &x){
static int f;
static char c;
c=gc(),f=1,x=0;
while(c<'0'||c>'9') f=(c=='-'?-1:1),c=gc();
while(c>='0'&&c<='9') x=10*x+c-'0',c=gc();
x*=f;
}
template<typename T> inline void putint(T x,char div){
static char s[15];
static int top;
top=0;
x<0?pc('-'),x=-x:0;
while(x) s[top++]=x%10,x/=10;
!top?pc('0'),0:0;
while(top--) pc(s[top]+'0');
pc(div);
}
}
using namespace iobuff;
const int N=3e5+10;
int n,m,tot;
int dfn[N],pos[N],mi[N],fa[N],f[N];
int semi[N],idom[N];
struct node{
int v,nxt;
};
struct graph{
int first[N],cnt;
node e[N];
inline void add(int u,int v){e[++cnt].v=v;e[cnt].nxt=first[u];first[u]=cnt;}
inline void init(){cnt=0;memset(first+1,0,sizeof(int)*(n));}
}g,rg,ng,tr;
inline void dfs(int u){
dfn[u]=++tot;pos[tot]=u;
for(int i=g.first[u];i;i=g.e[i].nxt){
int v=g.e[i].v;
if(!dfn[v]) fa[v]=u,dfs(v);
}
}
inline int find(int x){
if(f[x]==x) return x;
int t=f[x];f[x]=find(f[x]);
if(dfn[semi[mi[t]]]<dfn[semi[mi[x]]]) mi[x]=mi[t];
return f[x];
}
inline void findidom(){
for(int i=1;i<=n;++i) mi[i]=semi[i]=f[i]=i;
for(int i=n;i>=2;--i){
int u=pos[i],sem=n;
for(int j=rg.first[u];j;j=rg.e[j].nxt){
int v=rg.e[j].v;
if(dfn[v]<dfn[u]) sem=min(sem,dfn[v]);
else find(v),sem=min(sem,dfn[semi[mi[v]]]);
}
semi[u]=pos[sem];f[u]=fa[u];
ng.add(semi[u],u);
u=pos[i-1];
for(int j=ng.first[u];j;j=ng.e[j].nxt){
int v=ng.e[j].v;
find(v);
if(semi[mi[v]]==u) idom[v]=u;
else idom[v]=mi[v];
}
}
for(int i=2;i<=n;++i){
int u=pos[i];
if(idom[u]!=semi[u]) idom[u]=idom[idom[u]];
tr.add(idom[u],u);
}
}
int pa[N][20],dep[N],MX,q;
inline void dfs_tr(int u){
for(int i=1;(1<<i)<=dep[u];++i) pa[u][i]=pa[pa[u][i-1]][i-1];
for(int i=tr.first[u];i;i=tr.e[i].nxt){
int v=tr.e[i].v;
pa[v][0]=u;dep[v]=dep[u]+1;dfs_tr(v);
}
}
inline int LCA(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
int t=dep[u]-dep[v];
for(int i=MX;i>=0;--i) if(t&(1<<i)) u=pa[u][i];
if(u==v) return u;
for(int i=MX;i>=0;--i)
if(pa[u][i]!=pa[v][i]) u=pa[u][i],v=pa[v][i];
return pa[u][0];
}
int vis[N],pd[N];
int main(){
// freopen("dominator1.in","r",stdin);
read(n);read(m);read(q);
for(int i=1,u,v;i<=m;++i){
read(u);read(v);
g.add(u,v);rg.add(v,u);
}
MX=log2(n);
dfs(1);
findidom();
dep[1]=0;dfs_tr(1);
while(q--){
int u,v;read(u);read(v);
int lca=LCA(u,v);
memset(pd+1,0,sizeof(int)*(n));
memset(vis+1,0,sizeof(int)*(n));
int now=lca;
while(now){
pd[now]=1;
for(int i=tr.first[now];i;i=tr.e[i].nxt){
int v=tr.e[i].v;
pd[v]=1;
}
now=pa[now][0];
}
queue<int> q;q.push(v);
int ans=0;
while(!q.empty()){
int u=q.front();q.pop();
if(pd[u]) continue;vis[u]=1;
ans++;
for(int i=g.first[u];i;i=g.e[i].nxt){
int v=g.e[i].v;
if(!vis[v]&&!pd[v]) vis[v]=1,q.push(v);
}
}
putint(ans,'
');
}
flush();
return 0;
}