TJOI2015Day2测试总结

5 篇文章 0 订阅
1 篇文章 0 订阅

今天又测TJOI2015,结果170GG了(orzAk爷)。。。

T1:

http://www.lydsy.com/JudgeOnline/problem.php?id=3999

考试的时候就是被这题给坑了,一看到是树,还不会改形态,直接树剖,然后看到是差最大,于是想到差分,然后求最大子串和,结果树上差分写到死都写不对。。。在苦苦挣扎了2.5个小时后,终于机智的想到了直接线段树维护,update的时候用右边的最大值减左边的最小值就OK了,最后还是搞了出来(果然还是太弱了),后来加上丧病的优化后终于刷到了Rank 1


正常版

#include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=50011,maxm=maxn<<1,inf=~0u>>2;
int tot=0,now[maxn],son[maxm],pre[maxm];
void add(int a,int b){pre[++tot]=now[a]; now[a]=tot; son[tot]=b;}
void cc(int a,int b){add(a,b); add(b,a);}
int n,v[maxn];
inline void read(int &x){
    x=0; char ch=getchar();
    while (!isdigit(ch)) ch=getchar();
    for (;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
}
void init(){
    read(n); int a,b;
    for (int i=1;i<=n;++i) read(v[i]);
    for (int i=1;i<n;++i) read(a),read(b),cc(a,b);
}
int fa[maxn],top[maxn],dep[maxn],sz[maxn],dfn[maxn],seq[maxn];
void getdfn(){
    static int q[maxn]; int w=1; q[1]=1; fa[1]=0; dep[1]=0;
    for (int i=1;i<=w;++i) for (int p=now[q[i]];p;p=pre[p])
        if (fa[q[i]]!=son[p]) q[++w]=son[p],fa[q[w]]=q[i],dep[q[w]]=dep[q[i]]+1;
    for (int i=1;i<=n;++i) sz[i]=1,top[i]=i; dfn[1]=1;
    for (int i=w;i>=1;--i) sz[fa[q[i]]]+=sz[q[i]]; sz[0]=0;
    for (int i=1;i<=w;++i){
        int x=q[i],tmp=0,res=dfn[x];
        for (int p=now[x];p;p=pre[p]) if (son[p]!=fa[x] && sz[son[p]]>sz[tmp]) tmp=son[p];
        if (tmp){dfn[tmp]=res+1; res+=sz[tmp]; top[tmp]=top[x];}
        for (int p=now[x];p;p=pre[p]) if (son[p]!=fa[x] && son[p]!=tmp)
            dfn[son[p]]=res+1,res+=sz[son[p]];
    }
    for (int i=1;i<=n;++i) seq[dfn[i]]=i;
}
struct Tseg{
    struct node{
        int mn,mx,s1,s2,ad;
        void clear(){mn=inf; mx=-inf; s1=s2=0;}
        void merge(node a,node b){
            mx=max(a.mx,b.mx); mn=min(a.mn,b.mn);
            s1=max(max(a.s1,b.s1),b.mx-a.mn); s2=max(max(a.s2,b.s2),a.mx-b.mn);
        }
        void add(int add){
            ad+=add; mx+=add; mn+=add;
        }
    }e[maxn<<3];
    node inv(node x){swap(x.s1,x.s2); return x;}
    void push(int p){
        if (!e[p].ad) return;
        e[p<<1].add(e[p].ad); e[p<<1|1].add(e[p].ad);
        e[p].ad=0;
    }
    void build(int p,int l,int r){
        e[p].ad=0;
        if (l==r){
            e[p].mx=e[p].mn=v[seq[l]]; e[p].s1=e[p].s2=0; return;
        }
        int mid=(l+r)>>1;
        build(p<<1,l,mid); build(p<<1|1,mid+1,r);
        e[p].merge(e[p<<1],e[p<<1|1]);
    }
    void clear(){build(1,1,n);}
    void modify(int p,int l,int r,int fir,int las,int v){
        if (l==fir && r==las){e[p].add(v); return;}
        push(p); int mid=(l+r)>>1;
        if (las<=mid) modify(p<<1,l,mid,fir,las,v);
        else if (fir>mid) modify(p<<1|1,mid+1,r,fir,las,v);
        else modify(p<<1,l,mid,fir,mid,v),modify(p<<1|1,mid+1,r,mid+1,las,v);
        e[p].merge(e[p<<1],e[p<<1|1]);
    }
    node Query(int p,int l,int r,int fir,int las){
        if (l==fir && r==las) return e[p];
        push(p); int mid=(l+r)>>1;
        if (las<=mid) return Query(p<<1,l,mid,fir,las);
        else if (fir>mid) return Query(p<<1|1,mid+1,r,fir,las);
        node a; a.merge(Query(p<<1,l,mid,fir,mid),Query(p<<1|1,mid+1,r,mid+1,las));
        return a;
    }
     
    void modify(int a,int b,int v){
        while (top[a]!=top[b]){
            if (dep[top[a]]<dep[top[b]]) swap(a,b);
            modify(1,1,n,dfn[top[a]],dfn[a],v);
            a=fa[top[a]];
        }
        if (dep[a]>dep[b]) swap(a,b);
        modify(1,1,n,dfn[a],dfn[b],v);
    }
    int Query(int a,int b){
        node sa,sb; sa.clear(); sb.clear();
        while (top[a]!=top[b]){
            if (dep[top[a]]>dep[top[b]]){
                node x=Query(1,1,n,dfn[top[a]],dfn[a]);
                sa.merge(x,sa); a=fa[top[a]];
            }else{
                node x=Query(1,1,n,dfn[top[b]],dfn[b]);
                sb.merge(x,sb); b=fa[top[b]];
            }
        }
        if (dep[a]>dep[b])
            sa.merge(Query(1,1,n,dfn[b],dfn[a]),sa);
        else
            sb.merge(Query(1,1,n,dfn[a],dfn[b]),sb);
        sa.merge(inv(sa),sb); return sa.s1;
    }
}seg;
void work(){
    getdfn(); seg.clear();
    int q,a,b,v; read(q);
    while (q--){
        read(a); read(b); read(v);
        seg.modify(a,b,v); printf("%d\n",seg.Query(a,b));
    }
}
int main(){
    init(); work();
    return 0;
}

丧病版就不贴了吧。。



T2:

http://www.lydsy.com/JudgeOnline/problem.php?id=4000

这题看到就是状压Dp,但是怎么都是30分,于是就去写第1题去了,最后搞完第一题就没时间了,于是爆0

因为这题自己在中间一行,所以自己对上面一行的影响,可以变成上面一行对自己的影响,于是就是2行了

然后发现n很大,于是矩阵乘法优化,先把转移矩阵搞出来,然后快速幂求出来就OK了,因为mod 2^32,所以直接自然溢出

#include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
int M,n,m,a[5][100];
void init(){
    scanf("%d%d",&n,&m); M=1<<m; int len,w;
    scanf("%d%d",&len,&w); ++w;
    for (int i=1;i<=3;++i) for (int j=1;j<=len;++j)
        scanf("%d",&a[i][m+j-w]);
    for (int j=1;j<=2*m;++j) if (a[1][j])
        a[3][2*m-j]=1;
}
struct Tmx{
    static const int maxn=65;
    void clear(){memset(a,0,sizeof(a));}
    int a[maxn][maxn];
};/*
void mul(Tmx &a,Tmx b){
    Tmx c=a; a.clear();
    for (int i=0;i<M;++i) for (int j=0;j<M;++j)
        for (int k=0;k<M;++k) a.a[i][j]+=c.a[i][k]*b.a[k][j];
}*/
void mul(Tmx &res,Tmx b){
    Tmx a=res; res.clear(); int N=1<<m;
    for(int i=0;i<N;++i)
        for(int j=0;j<N;++j)if(a.a[i][j])
            for(int k=0;k<N;++k)if(b.a[j][k])
                res.a[i][k]+=a.a[i][j]*b.a[j][k];
}
Tmx power(Tmx a,int t){
    Tmx ans=a; --t;
    while (t){
        if (t&1) mul(ans,a);
        t>>=1; mul(a,a);
    }
    return ans;
}
bool check(int s){
    for (int i=0;i<m;++i) if ((s>>i)&1){
        for (int j=1;j<=2*m;++j) if (a[2][j]){
            int x=i-(m-j); if (x==i || x<0 || x>=m) continue;
            if (s&(1<<x)) return false;
        }
    }
    return true;
}
bool check(int s1,int s2){
    if (!check(s1) || !check(s2)) return false;
    for (int i=0;i<m;++i) if ((s1>>i)&1){
        for (int j=1;j<=2*m;++j) if (a[3][j]){
            int x=i-(m-j); if (x<0 || x>=m) continue;
            if (s2&(1<<x)) return false;
        }
    }
    return true;
}
Tmx aa;
void gao(){
    aa.clear();
    for (int i=0;i<M;++i) for (int j=0;j<M;++j) 
        if (check(i,j)) aa.a[i][j]=1;
}
void work(){
    gao(); aa=power(aa,n);
    Tmx b; b.clear();
    b.a[0][0]=1; for (int i=1;i<M;++i) b.a[0][i]=0;
    mul(b,aa); int ans=0; for (int i=0;i<M;++i) ans+=b.a[0][i];
    printf("%u\n",ans);
}
int main(){
    init(); work();
    fclose(stdin); fclose(stdout);
    return 0;
}

T3:

http://www.lydsy.com/JudgeOnline/problem.php?id=4001

这题O(n^2)非常水,设f[i]代表为i的期望叶子树,g[i]代表为i的同构数

那么很好递推,然后就这样70分了

但是这题有规律就是(n+1)*n/(4*n-2)

证明的话 http://blog.miskcoo.com/2015/04/bzoj-4001



70分

#include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1110;
typedef long double ld;
ld f[maxn]; ld g[maxn];
int main(){
//	freopen("prob.in","r",stdin); freopen("prob.out","w",stdout);
	int n; scanf("%d",&n);
	f[1]=1; g[1]=1; f[0]=0; g[0]=1;
	for (int i=2;i<=n;++i){
		g[i]=0; f[i]=0;
		for (int k=0;k<i;++k)
			g[i]+=g[k]*g[i-k-1];
		for (int k=0;k<i;++k)
			f[i]+=(g[k]*g[i-k-1])*(f[k]+f[i-k-1]);
		f[i]/=g[i];
	}
	printf("%.12f\n",(double)f[n]);
	fclose(stdin); fclose(stdout);
}


100分

include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
    int n; scanf("%d",&n);
    printf("%.9f\n",1.0*n*(n+1)/2/(2*n-1));
}



主要就是写了第一题进坑了,以后写之前还要考虑编程复杂度。。。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值