TJOI2015Day1测试总结

来源:互联网 发布:佛教的软件 编辑:程序博客网 时间:2024/06/11 04:44

好久没来过了。。。。

今天跟一群神犇测TJOI2015day1的题,除了我基本上都Ak了,蒟蒻的只有200分

T1:

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

这题不是很难,就是一个最小割,但是由于没有深入理解矩阵的乘法,结果想了1个小时左右才发现,当Ai,Aj同时为1时才可以获得Bij,而Ai为1又得付出Ci的代价,于是就写掉了

(这题数据真心水,把B的全部加上再减掉C的就可以A了)


#include<cmath>#include<cstdio>#include<cstring>#include<cassert>#include<iostream>#include<algorithm>using namespace std;const int inf=~0u>>2,maxn=511,maxm=maxn,maxe=maxm*maxm*2;int tot=1;int now[maxm],pre[maxe],son[maxe],v[maxe];void add(int a,int b,int c){pre[++tot]=now[a]; now[a]=tot; son[tot]=b; v[tot]=c;}void cc(int a,int b,int c){add(a,b,c); add(b,a,c);}void cc1(int a,int b,int c){add(a,b,c); add(b,a,0);}int st,ed,n,ans=0,a[maxn];void init(){scanf("%d",&n); int x; st=n+1; ed=st+1; memset(a,0,sizeof(a));for (int i=1;i<=n;++i)for (int j=1;j<=n;++j)scanf("%d",&x),cc(i,j,x),a[i]+=x,a[j]+=x,ans-=x;for (int i=1;i<=n;++i) scanf("%d",&x),cc1(st,i,2*x),cc1(i,ed,a[i]); }int dep[maxm];bool bfs(){static int q[maxm]; memset(dep,0,sizeof(dep));int w=1; q[w]=st; dep[st]=1;for (int i=1;i<=w;++i) for (int p=now[q[i]];p;p=pre[p])if (v[p] && !dep[son[p]]) q[++w]=son[p],dep[q[w]]=dep[q[i]]+1;return dep[ed]>0;}int find(int x,int f){if (x==ed) return f; int ans=0;for (int p=now[x];p;p=pre[p]) if (v[p] && dep[son[p]]>dep[x]){int k=find(son[p],min(f,v[p]));v[p]-=k; v[p^1]+=k; f-=k; ans+=k;if (!f) return ans;}dep[x]=0; return ans;}int maxflow(){int ans=0;while (bfs()) ans+=find(st,inf);return ans;}void work(){printf("%d\n",-(ans+maxflow()/2));}int main(){init();work();fclose(stdin); fclose(stdout);return 0;}



T2:

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

这题刚看到就YY了一个50分暴力,后来就进了第三题这个坑,最后这题就没写了

这题的话有两种做法

因为只能向下或者向右,我们设w[i*m+j]=a[i][j],h[i*m+j]=j,那么原题的就可以看成一个导弹拦截问题,w[i]代表这个位置上的导弹数,h[i]代表这个位置导弹的高度,那么

(在执行以下操作的过程中s[x]代表以x结尾的拦截还剩几个)

1、先将数量为0的导弹删掉

2、枚举每个点x

3、找到它前面第一个不比它高的最高的导弹a(找不到就到第4步),如果s[a]>=s[x],那么s[a]-=s[x](拦截完a后就拦截x),然后去第5步,否则s[x]-=s[a],把a删掉(从a出来的已经没有了),继续搞第3步

4、把答案加上s[x](表示要从x开始s[x]个拦截),去第5步

5、s[x]=w[x],然后去第2步

显然枚举每个点的时候,出了删点的过程,最多只会找到一个点,而每个点又只会被删一次,那么就是O(点数)的,但是还要找点删点,可以用个set维护,就是O(点数log点数)的,即O(n^2logn),这个已经可以过了,但是因为这题的特殊性质,可以优化到O(n^2)的,具体参见代码


还有一种很巧妙的做法,最小链覆盖=最长反链,先考虑每个格子只有0或者1,另x1<=x2的偏序关系就是(x1<x2 && y1<=y2) || x1==x2,那么反链就是x1<x2 && y1>y2,就是从右上到左下Dp一遍就行了,现在一个格子中有了多个,那么,另x1<=x2的偏序关系是(x1<x2 && y1<=y2) || (x1==x2 && y1!=y2),那么反链就是(x1<x2 && y1>y2) || (x1==x2 && y1==y2),于是惊讶的发现就是一个带权的Dp了,就O(n^2)了


前一种方法太神了没敢写,于是贴某Ak爷代码

O(n^2logn)

#include<algorithm>#include<iostream>#include<cstring>#include<cstdlib>#include<cassert>#include<cstdio>#include<cmath>#include<ctime>#include<map>using namespace std;typedef long long int64;const int maxn=1000010;int h[maxn],t[maxn];int q,sum,n,m;void init(){scanf("%d%d",&n,&m); sum=0;for(int i=1;i<=n;++i)for(int j=1;j<=m;++j){int v; scanf("%d",&v);if(v) ++sum,h[sum]=j,t[sum]=v;}}typedef multimap<int,int>::iterator iter;multimap<int,int> s; int f[maxn];void solve(){int64 ans=0; s.clear();memset(f,0,sizeof(f));for(int i=1;i<=sum;++i){for(iter x;f[i]<t[i];){x=s.upper_bound(h[i]); if(x==s.begin()) break;--x; int k=min(f[x->second],t[i]-f[i]);f[x->second]-=k,f[i]+=k;if(!f[x->second]) s.erase(x);}if(f[i]<t[i]) ans+=t[i]-f[i],f[i]=t[i];s.insert(make_pair(h[i],i));}cout<<ans<<endl;}int main(){for(scanf("%d",&q);q--;){init();solve();}return 0;}

优化后变成了O(n^2)   orz

#include<algorithm>#include<iostream>#include<cstring>#include<cstdlib>#include<cassert>#include<cstdio>#include<cmath>#include<ctime>#include<map>using namespace std;const int maxbuf=20000000;char buf[maxbuf],*wbuf=buf;inline int getint(){int x=0; for(;!isdigit(*wbuf);++wbuf);while(isdigit(*wbuf)) x=x*10+*wbuf++-'0'; return x;}typedef long long int64;const int maxn=1010;int64 f[maxn],g[maxn];int q,n,m;int main(){fread(buf,1,maxbuf,stdin);for(int q=getint();q--;){n=getint(),m=getint();memset(f,0,sizeof(f)); int64 ans=0;for(int i=1;i<=n;++i){int64 sum=0;memset(g,0,sizeof(g));for(int j=1;j<=m;++j){int v=getint(); sum+=f[j];if(f[j]>v) continue;g[j]=min(sum,v-f[j]);if(v>sum) ans+=v-sum,sum=v;f[j]=v;}for(int j=m,k=m-1;j>=1;--j){if(k>=j) k=j-1;for(;k;--k){int64 v=min(g[j],f[k]);g[j]-=v,f[k]-=v;if(!g[j]) break;}}}cout<<ans<<endl;}return 0;}

第二种方法


#include<cmath>#include<cstdio>#include<cstring>#include<cassert>#include<iostream>#include<algorithm>using namespace std;const int maxn=1011,maxbuf=20000000;char buf[maxbuf],*wbuf=buf;inline void read(int &x){x=0; while (!isdigit(*wbuf)) ++wbuf;while (isdigit(*wbuf)) x=x*10+*wbuf++-'0';}int a[maxn][maxn],f[maxn][maxn],n,m;void init(){read(n); read(m);for (int i=1;i<=n;++i) for (int j=1;j<=m;++j)read(a[i][j]);}void work(){for (int i=1;i<=m;++i) f[0][i]=0;for (int i=1;i<=n;++i) f[i][m+1]=0;for (int i=1;i<=n;++i) for (int j=m;j>=1;--j)f[i][j]=max(max(f[i-1][j+1]+a[i][j],f[i-1][j]),f[i][j+1]);cout<<f[n][1]<<endl;}int main(){fread(buf,1,maxbuf,stdin);int T; read(T);while (T--) init(),work();return 0;}


T3:

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

这题要求有关子串,就知道是后缀自动机,但是因为太弱了,后缀自动机写不出啊,于是就傻叉的写了后缀数组,虽然测试A掉了,但是bzoj交到死也TLE(某大神硬是DC3搞过去了orz)

先来讲一下后缀数组的写法吧,对于T=0的就是个论文题,来讲讲T=1的情况

首先按照后缀的排序枚举每个后缀

看这个后缀在所有子串中的排名,如果<rank就继续枚举,如果>=rank就二分一下在什么位置

统计的时候,要注意把下面与其相同的部分也统计掉,然后乱二分几下,就变成了O(nlogn)的了

后缀自动机果然还是得写啊。。。



死都TLE的

#include<cmath>#include<ctime>#include<cstdio>#include<cstring>#include<cassert>#include<iostream>#include<algorithm>#define min(a,b) ((a)<(b)?(a):(b))using namespace std;const int maxn=500011;typedef long long LL;char s[maxn]; int op,rk,n;void init(){scanf("%s%d%d",s,&op,&rk); n=strlen(s)+1;}int sa[maxn],rank[maxn],height[maxn];inline bool cmp(int *x,int a,int b,int len){return x[a]==x[b] && x[a+len]==x[b+len];}void suffix_sort(){static int wx[maxn],ws[maxn],wy[maxn]; int i,m=300,*x=wx,*y=wy;for (i=0;i<m;++i) ws[i]=0;for (i=0;i<n;++i) ++ws[x[i]=s[i]];for (i=1;i<m;++i) ws[i]+=ws[i-1];for (i=n-1;i>=0;--i) sa[--ws[x[i]]]=i;for (int len=1,p=0;p<n;len<<=1,m=p){for (p=0,i=n-len;i<n;++i) y[p++]=i;for (i=0;i<n;++i) if (sa[i]>=len) y[p++]=sa[i]-len;for (i=0;i<m;++i) ws[i]=0;for (i=0;i<n;++i) ++ws[x[y[i]]];for (i=1;i<m;++i) ws[i]+=ws[i-1];for (i=n-1;i>=0;--i) sa[--ws[x[y[i]]]]=y[i];for (swap(x,y),x[sa[0]]=0,i=p=1;i<n;++i) // y is rankx[sa[i]]=cmp(y,sa[i-1],sa[i],len)?p-1:p++;}for (int i=0;i<n;++i) rank[i]=x[i];}void get_height(){for (int i=0,j,len=0;i<n-1;height[rank[i++]]=len)for (len?--len:0,j=sa[rank[i]-1];s[i+len]==s[j+len];++len);}int rmq[maxn][22],lg2[maxn];void RMQ(){lg2[1]=0; for (int i=2;i<=n;++i) lg2[i]=lg2[i>>1]+1;for (int i=n-1;i>=1;--i){rmq[i][0]=height[i]; int x=lg2[n-i];for (int j=1;j<=x;++j)rmq[i][j]=min(rmq[i][j-1],rmq[i+(1<<(j-1))][j-1]);}}int Rget(int a,int b){int x=lg2[b-a+1];return min(rmq[a][x],rmq[b-(1<<x)+1][x]);}void prepare(){suffix_sort(); get_height(); RMQ();}LL f[maxn];LL Query(int s,int x){if (s==height[x]) return f[x];int t=x+1,w=n;while (t<=w){int mid=(t+w)>>1;if (Rget(x+1,mid)<s) w=mid-1;else t=mid+1;}++w; return (LL)s*(w-x)+f[w];}LL Query2(int s,int x){int t=x,w=n;while (t<=w){int mid=(t+w)>>1;if (Rget(x,mid)<s) w=mid-1;else t=mid+1;}++w; return (LL)s*(w-x)+f[w];}void write(int a,int len){for (int i=0;i<len;++i) putchar(s[a+i]); putchar('\n');}void work(){prepare(); --n;if (!op){for (int i=1;i<=n;++i){int sum=n-sa[i]-height[i];if (rk>sum) rk-=sum;else{write(sa[i],height[i]+rk); return;}}puts("-1"); return;}f[n+1]=0;for (int i=n;i>=1;--i){f[i]=Query2(height[i],i+1)+height[i];}for (int i=1;i<=n;++i){int len=n-sa[i]; LL tmp=f[i],res=Query(len,i)-tmp;if (rk>res) rk-=res;else{int t=height[i]+1,w=len;while (t<=w){int mid=(t+w)>>1;if (Query(mid,i)-tmp>=rk) w=mid-1;else t=mid+1;}write(sa[i],w+1); return;}}puts("-1"); return;}int main(){freopen("string.in","r",stdin);freopen("string.out","w",stdout);init();work();fclose(stdin); fclose(stdout);return 0;}

DC3的    orz

#include<bits/stdc++.h>using namespace std;#define X first#define Y second#define mp make_pair#define ph push#define pb push_back#define REP(i,a,n) for(int _tmp=n,i=a;i<=_tmp;++i)#define DEP(i,a,n) for(int _tmp=n,i=a;i>=_tmp;--i)#define rep(i,a,n) for(int i=(a);i<=(n);++i)#define dep(i,a,n) for(int i=(a);i>=(n);--i)#define ALL(x,S) for(__typeof((S).end()) x=S.begin();x!=S.end();x++)#define eps 1e-8#define pi 3.1415926535897#define sqr(x) ((x)*(x))#define MAX(a,b) a=max(a,b)#define MIN(a,b) a=min(a,b)#define SZ(x) ((int)(x).size())#define CPY(a,b) memcpy(a,b,sizeof(a))#define CLR(a) memset(a,0,sizeof(a))#define POSIN(x,y) (1<=(x)&&(x)<=n&&1<=(y)&&(y)<=m)#define all(x) (x).begin(),(x).end()#define COUT(S,x) cout<<fixed<<setprecision(x)<<S<<endltypedef long long ll;typedef double lf;typedef pair<int,int> pii;typedef pair<ll,ll> pll;typedef pair<lf,lf> pff;typedef complex<double> CD;const int inf=0x20202020;const int mod=1000000007;template<class T> inline void read(T&x){bool fu=0;char c;for(c=getchar();c<=32;c=getchar());if(c=='-')fu=1,c=getchar();for(x=0;c>32;c=getchar())x=x*10+c-'0';if(fu)x=-x;};template<class T> inline void read(T&x,T&y){read(x);read(y);}template<class T> inline void read(T&x,T&y,T&z){read(x);read(y);read(z);}template<class T> inline void read(T&x,T&y,T&z,T&q){read(x);read(y);read(z);read(q);}const int DX[]={1,0,-1,0},DY[]={0,1,0,-1};ll powmod(ll a,ll b) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}ll powmod(ll a,ll b,ll mod) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}//*******************************************#define rank orzlydconst int N=511111,M=111111;int l,m,n,C;char s[N],asks[N];int rank[N],rank2[N],pai[N],sa[N],rmq[22][N],height[N];ll h[N],x,y,hh[N];/*namespace SA{int *x=rank,*y=rank2,*t;bool cmp(int *y,int a1,int a2, int a3){return y[a1]==y[a2]&&y[a1+a3]==y[a2+a3];}bool scmp(const int &a, const int &b){return x[a]<x[b];}void calcsa(){    int j=1,p=1,m=20010;    rep(i,1,n) pai[i]=i,x[i]=s[i];    sort(pai+1,pai+n+1,scmp);    rep(i,1,n) sa[i]=pai[i+1];    for(;j<=n;j*=2,m=p){        p=1;rep(i,n-j,n-1) y[p++]=i;        rep(i,1,n) if(sa[i]>j) y[p++]=sa[i]-j;        rep(i,1,m) pai[i]=0;        rep(i,1,n) ++pai[x[y[i]]];        rep(i,2,m) pai[i]+=pai[i-1];        dep(i,n,1) sa[pai[x[y[i]]]--]=y[i];        t=x;x=y;y=t;p=2;x[sa[1]]=1;        rep(i,2,n) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;    }}void calch(){    int i,j,k=0;rep(i,0,n) rank[sa[i]]=i;    for(i=1;i<=n;h[rank[i++]]=k) for(k?k--:0,j=sa[rank[i]-1];s[i+k]==s[j+k];k++);}}*/namespace SAA{void init(){    int *x = rank, *y = height;     static int w[N];    for (int i = 1; i <= n; ++i)        ++w[x[i] = s[i] - 96];    for (int i = 2; i <= 126; ++i)        w[i] += w[i - 1];    for (int i = 1; i <= n; ++i)        sa[w[x[i]]--] = i;     for (int k = 1, m = 126; k < n; k <<= 1, swap(x, y))    {        int t = 0;        for (int i = n - k + 1; i <= n; ++i)            y[++t] = i;        for (int i = 1; i <= n; ++i)            if (sa[i] - k >= 1)                y[++t] = sa[i] - k;         memset(w + 1, 0, m << 2);        for (int i = 1; i <= n; ++i)            ++w[x[i]];        for (int i = 2; i <= m; ++i)            w[i] += w[i - 1];        for (int i = n; i; --i)            sa[w[x[y[i]]]--] = y[i];         m = 0;        for (int i = 1; i <= n; ++i)        {            int u = sa[i], v = sa[i - 1];            y[u] = i == 1 || x[u] != x[v] || x[u + k] != x[v + k] ? ++m : m;        }        if (m == n)            break;    }     if (y != rank)        memcpy(rank + 1, y + 1, n << 2);     for (int i = 1, h = 0; i <= n; ++i)    {        if (h)            --h;        int j = sa[rank[i] - 1];        while (s[i + h] == s[j + h])            ++h;        height[rank[i]] = h;    }}}int LOG[N];inline int RMQ(const int &l,const int &r){    if(l>r)return inf;    int p=LOG[r-l+1];    return min(rmq[p][l],rmq[p][r-(1<<p)+1]);}ll ta[N],tb[N],tp;int main(){    //ios::sync_with_stdio(false);    freopen("string.in","r",stdin);freopen("string.out","w",stdout);    rep(i,1,20)LOG[1<<i]=i;    rep(i,2,500000)if(!LOG[i])LOG[i]=LOG[i-1];    for(s[1]=getchar();s[1]<'a'||s[1]>'z';s[1]=getchar());n=1;    for(;s[n]>='a'&&s[n]<='z';s[++n]=getchar());s[n]=0;--n;    //printf("%d %s\n",n,s+1);    //SA::calcsa();SA::calch();    SAA::init();rep(i,1,n)h[i]=height[i];    //rep(i,1,n)printf("%d %d %lld\n",i,sa[i],h[i]);    ++n;    rep(i,1,n)rmq[0][i]=h[i];    rep(i,1,20)rep(j,1,n){        if(j+(1<<i-1)>n)break;        rmq[i][j]=min(rmq[i-1][j],rmq[i-1][j+(1<<i-1)]);    }    //return 0;    //printf("%d\n",clock());    read(x,y);    if(x==0){        h[0]=0;        rep(i,1,n)h[i]=h[i-1]+(n-sa[i])-h[i];                 int Min=1,Max=n,pt,len;        while(Min<Max){            int mid=Min+Max>>1;if(h[mid]<y)Min=mid+1;else Max=mid;        }        if(Min==n){puts("-1");return 0;}        pt=Min;len=y-h[pt-1]+rmq[0][pt]-1;pt=sa[Min];        rep(i,pt,pt+len)putchar(s[i]);puts("");    }else{        if(y>n*(n-1)/2){puts("-1");return 0;}        ll res=0;tp=0;        dep(i,n,1){            while(tp&&h[ta[tp]]>=h[i])--tp;ta[++tp]=i;tb[tp]=hh[i-1]=tb[tp-1]+(ta[tp-1]-i)*h[i];        }        //rep(i,1,n)printf("%d %d %lld %lld\n",i,sa[i],h[i],hh[i]);        ll sum=0;        rep(i,1,n){            sum+=(n-sa[i]);if(sum+hh[i]>=y){                int pos;                dep(j,n-sa[i],1){                    int Min=i,Max=n,pt,len;                    while(Min<Max){                        int mid=Min+Max+1>>1;if(RMQ(i+1,mid)>=j)Min=mid;else Max=mid-1;                    }                    //printf("%d-%d\n",j,Min);                    y+=Min-i+1;                    if(sum+hh[i]<y){pos=j;break;}                }                rep(j,sa[i],sa[i]+pos-1)putchar(s[j]);                //printf("%d %d\n",i,pos);                break;            }        }    }    //printf("\n%d\n",clock());    return 0;}





自动机的

#include<cmath>#include<cstdio>#include<cstring>#include<cassert>#include<iostream>#include<algorithm>using namespace std;typedef long long LL;const int maxn=500011;char s[maxn]; int op,rank;void init(){scanf("%s%d%d",s,&op,&rank);}struct Tsam{struct node{node *ch[26],*f; int ml,s,sz; LL sum;int get(int op){return op?sum:sz;}void clear(){memset(ch,0,sizeof(ch)); f=0; ml=s=0; sz=1; sum=0;}}e[maxn<<1],*root,*last;int tot;node *newnode(){e[tot].clear(); return &e[tot++];}void clear(){tot=0; last=root=newnode();}void ins(int c){node *np=newnode(),*p=last; np->ml=p->ml+1; np->s=1;for (last=np;p && !p->ch[c];p=p->f) p->ch[c]=np;if (!p) {np->f=root; return;} node *q=p->ch[c];if (p->ml+1==q->ml){np->f=q; return;}node *r=newnode(); *r=*q; r->ml=p->ml+1; r->s=0;for (np->f=q->f=r;p && p->ch[c]==q;p=p->f) p->ch[c]=r;}void Dp(){static node *q[maxn<<1]; q[1]=root;static int ws[maxn<<1]; memset(ws,0,sizeof(ws));for (int i=0;i<tot;++i) ++ws[e[i].ml];for (int i=1;i<=tot;++i) ws[i]+=ws[i-1];for (int i=0;i<tot;++i) q[ws[e[i].ml]--]=e+i;for (int i=tot;i>=1;--i){q[i]->sum+=q[i]->s;for (int c=0;c<26;++c) if (q[i]->ch[c])q[i]->sz+=q[i]->ch[c]->sz,q[i]->sum+=q[i]->ch[c]->sum;if (q[i]->f) q[i]->f->s+=q[i]->s;}}void getans(int op,int rank){Dp(); rank+=op?root->s:1;if (root->get(op)<rank){puts("-1"); return;}for (node *p=root;;){rank-=op?p->s:1; if (!rank) return;for (int c=0;c<26;++c) if (p->ch[c]){int tmp=p->ch[c]->get(op);if (tmp<rank) rank-=tmp;else {putchar('a'+c); p=p->ch[c]; break;}}}}}sam;void work(){sam.clear(); for (int i=0;s[i];++i) sam.ins(s[i]-'a');sam.getans(op,rank);}int main(){init();work();return 0;}




在看到第一题的时候,没有很快想出模型,第二题也是根本没有想到Dilworth定理(导弹拦截的模型转化也没想到),第三题虽然过了,但是改了太久,主要是因为把数组的意义搞混乱了,以后要注意数组的真实含义


0 0
原创粉丝点击