zoukankan      html  css  js  c++  java
  • THUSC2016

    补退选

    Luogu
    LOJ
    BZOJ
    比较裸。
    建一棵Trie树,记录一下每个节点的(sum)表示经过该点的字符串个数,每次暴力插入、删除。
    同时每个节点维护一个vector,记录一下这个点的(sum)第一次达到(超过)某个值的时间。
    容易证明vector的总的元素个数是(O(sum|S|))的。总的复杂度为(O(sum|S|))

    #include<bits/stdc++.h>
    using namespace std;
    const int N=100007,M=60*N;
    int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=x*10+c-48,c=getchar();return x;}
    int T=1,cnt,ans,sum[M],ch[M][10];vector<int>t[M];char s[61];
    void update(int p)
    {
        if(sum[p]<=(int)t[p].size()) return ;
        t[p].push_back(T);
    }
    void insert()
    {
        scanf("%s",s);int len=strlen(s),p=0;++sum[p],update(p);
        for(int i=0,c;i<len;++i)
        {
    	if(!ch[p][c=s[i]-'a']) ch[p][c]=++cnt;
    	++sum[p=ch[p][c]],update(p);
        }
    }
    void remove()
    {
        scanf("%s",s);int len=strlen(s),p=0;--sum[p];
        for(int i=0,c;i<len;++i) --sum[p=ch[p][c=s[i]-'a']];
    }
    void query()
    {
        scanf("%s",s);
        int a=read(),b=read(),c=read(),len=strlen(s),p=0;
        a=(1ll*a*abs(ans)+b)%c;
        for(int i=0;i<len;++i) if(!(p=ch[p][s[i]-'a'])) return (void)(printf("%d
    ",ans=-1));
        if((int)t[p].size()<=a) return (void)(printf("%d
    ",ans=-1));
        printf("%d
    ",ans=t[p][a]);
    }
    int main()
    {
        for(int m=read();T<=m;++T)
    	switch(read())
    	{
    	case 1:insert();break;
    	case 2:remove();break;
    	case 3:query();break;
    	}
    }
    

    成绩单

    Luogu
    LOJ
    BZOJ
    看到数据范围基本上区间dp没得跑了,这东西大概能够容忍(O(n^5))的时间复杂度和(O(n^4))的空间复杂度。(虽然感觉时间复杂度(O(n^6))也完全没问题...)
    那么我们就可以把有用的四个东西全部放进我们的状态。
    (f_{l,r,x,y})表示([l,r])区间,剩下的数在([x,y])范围内(记得离散化)的最小代价。然后我们发现这东西不好表示区间全部被消掉的情况,而这正是我们需要求的,所以我们再开一个(g_{l,r})表示消掉([l,r])区间的最小代价。
    考虑如何从([l,r-1])扩展到([l,r])
    针对(w_r)这一元素,我们有两种转移:(总的取(min)
    (1.)不管它。
    (f_{l,r,min(w_r,x),max(w_r,y)}leftarrow f_{l,r-1,x,y})
    (2.)([l,r-1])找一个后缀跟它一起消掉。
    (f_{l,r,x,y}leftarrow f_{l,k,x,y}+g_{k+1,r} kin[l,r))
    同时显然有(g_{l,r}=min(f_{l,r,x,y}+(t_y-t_x)^2))。((t_x)表示去重后(x)的原值)
    最后的答案就是(g_{1,n})
    注意转移顺序需要满足拓扑序,即先从小到大枚举区间长度再从左往右枚举左端点。
    初值(f_{i,i,w_i,w_i}=0,g_{i,i}=a),其它的都是(+infty)

    #include<bits/stdc++.h>
    using namespace std;
    int read(){int x;scanf("%d",&x);return x;}
    int max(int a,int b){return a>b? a:b;}
    int min(int a,int b){return a<b? a:b;}
    int sqr(int x){return x*x;}
    const int N=51;
    int w[N],t[N],f[N][N][N][N],g[N][N];
    int main()
    {
        int n=read(),m=n,a=read(),b=read();
        for(int i=1;i<=n;++i) w[i]=t[i]=read();
        sort(t+1,t+n+1),m=unique(t+1,t+n+1)-t-1,memset(f,0x3f,sizeof f),memset(g,0x3f,sizeof g);
        for(int i=1;i<=n;++i) w[i]=lower_bound(t+1,t+m+1,w[i])-t,f[i][i][w[i]][w[i]]=0,g[i][i]=a;
        for(int len=1,l,r,x,y,k;len<n;++len)
    	for(l=1,r=l+len;r<=n;++l,++r)
    	{
    	    f[l][r][w[r]][w[r]]=g[l][r-1];
    	    for(x=1;x<=m;++x) for(y=x;y<=m;++y) f[l][r][min(x,w[r])][max(y,w[r])]=min(f[l][r][min(x,w[r])][max(y,w[r])],f[l][r-1][x][y]);
    	    for(k=l;k<r;++k) for(x=1;x<=m;++x) for(y=x;y<=m;++y) f[l][r][x][y]=min(f[l][r][x][y],f[l][k][x][y]+g[k+1][r]);
    	    for(x=1;x<=m;++x) for(y=x;y<=m;++y) g[l][r]=min(g[l][r],f[l][r][x][y]+a+b*sqr(t[y]-t[x]));
    	}
        printf("%d",g[1][n]);
    }
    

    星露谷物语

    LOJ

  • 相关阅读:
    遍历进程,获取当前进程下进程的路径.(获得全路径)
    获得当前EIP的值
    反调试收集网址,待更新.
    python学习第八讲,python中的数据类型,列表,元祖,字典,之字典使用与介绍
    python学习第七讲,python中的数据类型,列表,元祖,字典,之元祖使用与介绍
    【Unity】2.4 层次视图(Hierarchy)
    【Unity】2.3 项目浏览器和资源的组织
    破解Unity5.3.4f1
    【Unity】2.2 Unity编辑器中的常用菜单项
    【Unity】2.1 初识Unity编辑器
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12004770.html
Copyright © 2011-2022 走看看