zoukankan      html  css  js  c++  java
  • 模板整理——dp,字符串及其他

    - dp

    鬼知道我为啥把这么重要的东西放最后面啊。

    考虑设计无后效性的状态,减小运算量。

    - 背包

    #include"iostream"
    #include"cstdio"
    #include"cmath"
    using namespace std;
    
    #define read(x) scanf("%d",&x)
    #define MAXN 1005
    
    int n,w[MAXN],v[MAXN],m;
    int dp[MAXN];
    int ans=0;
    
    int main()
    {
        read(m),read(n);   
        for(int i=1;i<=n;i++) read(w[i]),read(v[i]);
        for(int i=1;i<=n;i++)
        {
            for(int j=m;j>=w[i];j--) dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
        }
        for(int i=1;i<=m;i++) ans=max(dp[i],ans);
        return printf("%d
    ",ans),0;
    }
    
    #include"iostream"
    #include"cstdio"
    #include"cmath"
    using namespace std;
    
    #define read(x) scanf("%d",&x)
    #define ll long long
    
    int n,w[10005],v[10005],m;
    ll dp[10000005];
    ll ans=0;
    
    int main()
    {
        read(m),read(n);   
        for(int i=1;i<=n;i++) read(w[i]),read(v[i]);
        for(int i=1;i<=n;i++)
        {
            for(int j=w[i];j<=m;j++) dp[j]=max(dp[j],dp[j-w[i]]+(ll)v[i]);
        }
        for(int i=1;i<=m;i++) ans=max(dp[i],ans);
        return printf("%lld
    ",ans),0;
    }
    
    #include"iostream"
    #include"cstdio"
    #include"cmath"
    using namespace std;
    
    int dp[1005];
    int n,m;
    int w[10005],v[10005],c[10005];
    int h1,h2,m1,m2;
    int ans=0;
    
    int main()
    {
        scanf("%d:%d%d:%d%d",&h1,&m1,&h2,&m2,&n);
        if(m2>=m1) m=(m2-m1)+60*(h2-h1);
        else m=(m2-m1+60)+60*(h2-h1-1);
        for(int i=1;i<=n;i++) scanf("%d%d%d",&w[i],&v[i],&c[i]);
        for(int i=1;i<=n;i++)
        {
            if(!c[i]) c[i]=1<<20;
            for(int k=1;c[i]>0;k<<=1)
            {
                int kk=min(k,c[i]);
                for(int j=m;j>=kk*w[i];j--) dp[j]=max(dp[j],dp[j-kk*w[i]]+kk*v[i]);
                c[i]-=kk;//一定要随拆随算
            }
        }
        for(int i=1;i<=m;i++) ans=max(ans,dp[i]);
        printf("%d
    ",ans);
    }
    
    • 单调队列优化((mathcal O(nm))

    字母错一个,调题一万年。

    #include"iostream"
    #include"cstring"
    #include"cstdio"
    #include"cmath"
    using namespace std;
    
    int dp[1005];
    int n,m;
    int w[10005],v[10005],c[10005];
    int h1,h2,m1,m2;
    int ans=0;
    int q[1005],loc[1005];
    int d[1005];
    int tail,head=0;
    
    int main()
    {
        scanf("%d:%d%d:%d%d",&h1,&m1,&h2,&m2,&n);
        if(m2>=m1) m=(m2-m1)+60*(h2-h1);
        else m=(m2-m1+60)+60*(h2-h1-1);
        for(int i=1;i<=n;i++) scanf("%d%d%d",&w[i],&v[i],&c[i]);
        for(int i=1;i<=n;i++)
        {
            if(!c[i])
                for(int j=w[i];j<=m;j++) dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
            else
            {
                for(int j=0;j<=m;j++) d[j]=dp[j];//这个地方可能重复更新,而且不容易像01背包一样去倒叙枚举,所以这样改比较好
                for(int k=0;k<w[i];k++)
                {
                    head=0,tail=1,q[1]=0,loc[1]=0;
                    for(int j=0;j*w[i]+k<=m;j++)
                    {
                        d[k+j*w[i]]=max(d[k+j*w[i]],q[tail]+j*v[i]);
                        while(head>=tail&&dp[k+j*w[i]]-j*v[i]>=q[head]) head--;
                        q[++head]=dp[k+j*w[i]]-j*v[i],loc[head]=j;
                        while(loc[tail]<=j-c[i]) tail++;
                    }
                }
                for(int j=0;j<=m;j++) dp[j]=d[j];
            }
        }
        for(int i=1;i<=m;i++) ans=max(ans,dp[i]);
        printf("%d
    ",ans);
        return 0;
    }
    
    #include"algorithm"
    #include"iostream"
    #include"cstring"
    #include"cstdio"
    #include"cmath"
    using namespace std;
    
    #define MAXN 1005
    #define read(x) scanf("%d",&x)
    
    int n,m;
    struct node
    {
        int w,v,c;
    }a[MAXN];
    int dp[MAXN],cnt[MAXN],ans=0,cp=0;
    
    bool cmp(node n,node m){return n.c<m.c;}
    
    int main()
    {
        read(m),read(n);
        for(int i=1;i<=n;i++) read(a[i].w),read(a[i].v),read(a[i].c);
        sort(a+1,a+n+1,cmp);
        int lst=0;
        for(int i=1;i<=n;i++)
        {
             if(a[i].c!=lst) cp++,lst=a[i].c;
             cnt[cp]++;
        }
        int now=0;
        for(int i=1;i<=cp;i++)
        {
            for(int j=m;j>=0;j--)
            {
                lst=now;
                for(int k=1;k<=cnt[i];k++)
                {
                    lst++;
                    if(j<a[lst].w) continue;
                    dp[j]=max(dp[j],dp[j-a[lst].w]+a[lst].v);
                }
                if(!j) now=lst;
            }
        }
        for(int i=1;i<=m;i++) ans=max(ans,dp[i]);
        printf("%d
    ",ans);
        return 0;
    }
    

    - 最长上升子序列(LIS)(mathcal O(nlog n))

    这是个套着 (LCS) 皮的 (LIS)

    • 朴素做法(二分)
    #include"iostream"
    #include"cstdio"
    #include"cmath"
    using namespace std;
    
    #define MAXN 100005
    #define read(x) scanf("%d",&x)
    
    int n,x;
    int a[MAXN],b[MAXN];
    int now[MAXN],len=1;
    
    int main()
    {
        read(n);
        for(int i=1;i<=n;i++) read(x),b[x]=i;
        for(int i=1;i<=n;i++) read(x),a[i]=b[x];
        now[1]=a[1];
        for(int i=2;i<=n;i++)
        {
            int l=1,r=len,mid;
            if(a[i]>now[len]){now[++len]=a[i];continue;}
            while(l<r)
            {
                mid=(l+r)>>1;
                if(now[mid]<a[i]) l=mid+1;
                else r=mid;
            }
            if(l<len&&now[l]<a[i]) l--;
            now[l]=a[i];
        }
        printf("%d
    ",len);
        return 0;
    }
    
    • 大常数解法(线段树)

    请参考 P2215

    #include"algorithm"
    #include"iostream"
    #include"cstdio"
    #include"cmath"
    using namespace std;
    
    #define read(x) scanf("%d",&x)
    #define MAXN 10005
    
    struct num
    {
        int val,id;
    }b[MAXN];
    int n,m;
    struct node
    {
        int l,r,rec;
    }a[MAXN<<2];
    int re[MAXN],dp[MAXN];
    int l,me[MAXN];
    
    bool cmp(num n,num m){if(n.val==m.val) return n.id>m.id;else return n.val<m.val;}
    
    void hash()
    {
        sort(b+1,b+n+1,cmp);
        for(int i=1;i<=n;i++) re[b[i].id]=i,dp[i]=-1;
    }
    
    void update(int k){a[k].rec=max(a[k<<1].rec,a[k<<1|1].rec);}
    
    void build(int k,int l,int r)
    {
        a[k].l=l,a[k].r=r;
        if(l==r){a[k].rec=dp[l];return;}
        int mid=(l+r)>>1;
        build(k<<1,l,mid),build(k<<1|1,mid+1,r);
        update(k);
        return;
    }
    
    void modify(int k,int x,int y)
    {
        if(a[k].l==a[k].r){a[k].rec=y;return;}
        if(a[k<<1].r>=x) modify(k<<1,x,y);
        else modify(k<<1|1,x,y);
        update(k);
    }
    
    int query(int k,int l,int r)
    {
        if(a[k].l==l&&a[k].r==r) return a[k].rec;
        int mid=(a[k].l+a[k].r)>>1;
        if(r<=mid) return query(k<<1,l,r);
        else if(l>mid) return query(k<<1|1,l,r);
        else return max(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
    }
    
    int main()
    {
        read(n);
        for(int i=1;i<=n;i++) read(b[i].val),me[i]=b[i].val,b[i].id=i;
        hash(),build(1,1,n);
        for(int i=n;i>=1;i--)
        {
            int now=query(1,re[i],n);
            if(now==-1) dp[i]=1;
            else dp[i]=now+1;
            modify(1,re[i],dp[i]);
        }
        read(m);
        while(m--)
        {
            read(l);
            int now=l,lst=-0x7fffffff;
            for(int i=1;i<=n;i++)
            {
                if(dp[i]>=now&&me[i]>lst)
                {
                    now--,lst=me[i];
                    printf("%d ",me[i]);
                    if(now==0) break;
                }
            }
            if(now>0) printf("Impossible");
            puts("");
        }
        return 0;
    }
    

    - 字符串

    这个东西我真的不大会啊/kk。

    - 字符串哈希(这里直接使用双模哈希)((mathcal O(nm+nlog n))

    #include"algorithm"
    #include"iostream"
    #include"cstring"
    #include"cstdio"
    #include"cmath"
    using namespace std;
    
    #define MOD 1777777777
    #define MoD 1000000007
    
    int n;
    struct str
    {
    	int len,op,rt;
    	str(){op=rt=0;}
    }s[10005];
    char c[1505];
    int mio[1505],mir[1505];
    int ans=0;
    
    int tran(char s)
    {
    	if(s>='a'&&s<='z') return s-'a';
    	else if(s>='A'&&s<='Z') return s-'A'+26;
    	else return s-'0'+52;
    }
    
    bool cmp(str s,str t)
    {
    	if(s.len==t.len)
    	{
    		if(s.op==t.op) return s.rt<t.rt;
    		return s.op<t.op;
    	}
    	return s.len<t.len;
    }
    
    int main()
    {
    	scanf("%d",&n);
    	mio[0]=62,mir[0]=62;
    	for(int i=1;i<=1501;i++)
    	{
    		mio[i]=1ll*mio[i-1]*62ll%MOD;
    		mir[i]=1ll*mir[i-1]*62ll%MoD;
    	}
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%s",c);
    		s[i].len=strlen(c);
    		for(int j=0;j<s[i].len;j++)
    		{
    			s[i].op=(s[i].op+1ll*mio[j]*tran(c[j])%MOD)%MOD;
    			s[i].rt=(s[i].rt+1ll*mir[j]*tran(c[j])%MoD)%MoD;
    		}
    	}
    	sort(s+1,s+n+1,cmp);
    	ans=1;
    	for(int i=2;i<=n;i++)
    	{
    		if(s[i].len==s[i-1].len&&s[i].op==s[i-1].op&&s[i].rt==s[i-1].rt) continue;
    		else ans++;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

    - 字典树(Trie)(mathcal O(sum len))

    #include"iostream"
    #include"cstdio"
    #include"cmath"
    #include"cstring"
    using namespace std;
    
    #define MAXN 500005
    
    struct node
    {
        int son[27],t;
    }a[MAXN];
    int n,m;
    char c[55];
    int cnt=0;
    
    void add(string s)
    {
        int p=0,len=s.size();
        for(int i=0;i<len;i++)
        {
            if(!a[p].son[s[i]-'a']) a[p].son[s[i]-'a']=++cnt;
            p=a[p].son[s[i]-'a'];
        }
        a[p].t++;
    }
    
    int find(string s)
    {
        int p=0,len=s.size();
        for(int i=0;i<len;i++)
        {
            if(!a[p].son[s[i]-'a']) return -1;
            p=a[p].son[s[i]-'a'];
        }
        if(a[p].t){a[p].t--;return 1;}
        else return 2;
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",c);
            add(c);
        }
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%s",c);
            int opt=find(c);
            if(opt==-1) puts("WRONG");
            else if(opt==1) puts("OK");
            else puts("REPEAT");
        }
        return 0;
    }
    

    - KMP字符串匹配(mathcal O(n+m))

    #include"cstdio"
    #include"cstring"
    #include"iostream"
    using namespace std;
    
    #define MAXN 1000005
    
    char s[MAXN],t[MAXN];
    int f[MAXN],nxt[MAXN];
    int tl,sl;
    
    void get()
    {
        nxt[1]=0;
        for(int i=2;i<=tl;i++)
        {
            int k=nxt[i-1];
            while(k>0&&t[k+1]!=t[i]) k=nxt[k];
            nxt[i]=(t[k+1]==t[i])?k+1:0;
        }
        return;
    }
    
    void KMP()
    {
        f[1]=(s[1]==t[1])?1:0;
        for(int i=2;i<=sl;i++)
        {
            int k=f[i-1];
            while(t[k+1]!=s[i]&&k>0) k=nxt[k];
            f[i]=(t[k+1]==s[i])?k+1:0;
            if(f[i]==tl) printf("%d
    ",i-tl+1);
        }
        return;
    }
    
    int main()
    {
        scanf("%s%s",s,t);
        tl=strlen(t),sl=strlen(s);
        for(int i=tl;i>=1;i--) t[i]=t[i-1];
        for(int i=sl;i>=1;i--) s[i]=s[i-1];
        get(),KMP();
        for(int i=1;i<=tl;i++) printf("%d ",nxt[i]);
        return puts(""),0;
    }
    

    - manacher算法(mathcal O(n))

    应该考不到吧,不复习了qwq。

    - AC自动机(简单版)

    - AC自动机(加强版)

    - AC自动机(二次加强版)(都是 (mathcal O(sizesum len))

    放到这里,表示我曾经会

    - 其他

    - 二分查找((mathcal O(mlog n))

    请自动忽略缩进问题/kk。

    	//最后一个比他小的数 
    	read(n),read(m);
    	for(int i=1;i<=n;i++) read(a[i]);
    	sort(a+1,a+n+1);
    	for(int i=1;i<=m;i++)
    	{
    		read(x);
    		int l=1,r=n,mid;
    		while(l<r)
    		{
    			mid=(l+r)>>1;
    			if(a[mid]>=x) r=mid;
    			else l=mid+1;
    		}
    		if(a[l]>=x) l--;
    		if(a[1]>=x) puts("NO!");
    		else printf("%d
    ",a[l]);
    		cout<<endl;
    	}
    	return 0;
    
    	//最后一个比他小或等于的数 
    	read(n),read(m);
    	for(int i=1;i<=n;i++) read(a[i]);
    	sort(a+1,a+n+1);
    	for(int i=1;i<=m;i++)
    	{
    		read(x);
    		int l=1,r=n,mid;
    		while(l<r)
    		{
    			mid=(l+r)>>1;
    			if(a[mid]>x) r=mid;
    			else l=mid+1;	
    		}
    		if(a[l]>x) l--;
    		if(a[1]>x) puts("NO!");
    		else printf("%d
    ",a[l]); 
    	}
    	return 0;	
      	
       	//第一个比他大的数 
    	read(n),read(m);
    	for(int i=1;i<=n;i++) read(a[i]);
    	sort(a+1,a+n+1,cmp);
    	for(int i=1;i<=m;i++)
    	{
    		read(x);
    		int l=1,r=n,mid;
    		while(l<r)
    		{
    			mid=(l+r)>>1;
    			if(a[mid]<=x) r=mid;
    			else l=mid+1; 
    		}
    		if(a[l]<=x) l--;
    		if(x>=a[1]) puts("NO!");
    		else printf("%d
    ",a[l]);
    	}
    	return 0;			
        
    	//第一个比他大或等于的数 
    	read(n),read(m);
    	for(int i=1;i<=n;i++) read(a[i]);
    	sort(a+1,a+n+1,cmp);
    	for(int i=1;i<=m;i++)
    	{
    		read(x);
    		int l=1,r=n,mid;
    		while(l<r)
    		{
    			mid=(l+r)>>1;
    			if(a[mid]<x) r=mid;
    			else l=mid+1;
    		}
    		if(a[l]<x) l--;
    		if(a[1]<x) puts("NO!");
    		else printf("%d
    ",a[l]);
    	}
    	return 0;
    

    - 归并排序(mathcal O(nlog n))

    #include"iostream"
    #include"cstdio"
    #include"cmath"
    using namespace std;
    
    #define MAXN 100005 
    
    int n;
    int a[MAXN],rt[MAXN];
    
    void qsort(int l,int r)
    {
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	qsort(l,mid),qsort(mid+1,r);
    	int c=l-1,i=l,j=mid+1;
    	while(i<=mid&&j<=r)
    	{
    		if(a[i]<=a[j]) rt[++c]=a[i++];
    		else rt[++c]=a[j++];
    	}
    	while(i<=mid) rt[++c]=a[i++];
    	while(j<=r) rt[++c]=a[j++];
    	for(i=l;i<=r;i++) a[i]=rt[i]; 
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    	qsort(1,n);
    	for(int i=1;i<=n;i++) printf("%d ",a[i]);
    	return puts(""),0;
    }
    

    - 利用归并排序求逆序对(mathcal O(nlog n))

    #include"iostream"
    #include"cstdio"
    #include"cmath"
    using namespace std;
    
    #define MAXN 500005 
    
    int n;
    int a[MAXN],rt[MAXN];
    long long ans=0;
    
    void qsort(int l,int r)
    {
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	qsort(l,mid),qsort(mid+1,r);
    	int c=l-1,i=l,j=mid+1;
    	while(i<=mid&&j<=r)
    	{
    		if(a[i]<=a[j]) rt[++c]=a[i++];
    		else rt[++c]=a[j++],ans+=(long long)(mid-i+1);
    	}
    	while(i<=mid) rt[++c]=a[i++];
    	while(j<=r) rt[++c]=a[j++];
    	for(i=l;i<=r;i++) a[i]=rt[i]; 
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    	qsort(1,n);
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    注:逆序对还可以利用树状数组来求,是一种二位偏序的思想,这里就不赘述了。

    - 二维差分:

    对于矩阵 ({a_{i,j}}),其查分数组计算方法为 ({p_{i,j}=a_{i,j}-a_{i-1,j}-a_{i,j-1}+a_{i-1,j-1}})

    同时还原出原数 ({a_{i,j}=sumlimits_{k=1}^isumlimits_{l=1}^jp_{k,l}})

    可以类比一维差分与前缀和进行记忆。

    快速修改。

    比如说你要对 ((x_1,y_1):(x_2,y_2)) 区间 (+1)

    画图模拟一下就知道应该对差分数组实施:

    [p_{x_1,y_1}+1,p_{x_1,y_2+1}-1,p_{x_2+1,y_1}-1,p_{x_2+1,y_2+1}+1 ]

    - 一个常用的结论

    如这个题(Link),我们考虑把操作的分成两组考虑。

    1. 获得大于 (0)

    显然按消耗值从小到大排序。

    1. 获得小于 (0)(消耗)

    显然这种不能简单的贪心,记住下面这个结论:

    按 消耗与需求的和从大到小排序。

    总起来,当然先做获得大于 (0) 的操作。

    - 模拟退火(mathcal O( ext{可能能过}))

    #include"iostream"
    #include"cstdio"
    #include"cmath"
    #include"algorithm"
    #include"ctime"
    using namespace std;
    
    double xo[1005],yo[1005],m[1005];
    int n;
    double ansx,ansy,x,y,X,Y;
    double minx=10000000000.00;
    
    double f(double xx,double yy)
    {
        double ans=0;
        for(int i=1;i<=n;i++) ans+=sqrt((xx-xo[i])*(xx-xo[i])+(yy-yo[i])*(yy-yo[i]))*m[i];
        return ans;
    }
    
    void SA()
    {
        double T=13000,delta=0.993,T0=1e-15;
        while(T>T0)
        {
            X=x+((rand()<<1)-RAND_MAX)*T;
            Y=y+((rand()<<1)-RAND_MAX)*T;
            double op=f(X,Y);
            if(op<minx) minx=op,ansx=x=X,ansy=y=Y;
            else if(exp((minx-op)/T)*RAND_MAX>rand()) x=X,y=Y;
        	T*=delta;
         }
    }
    
    void work(){while((double)clock()/CLOCKS_PER_SEC<0.9) SA();}
    
    int main()
    {
        srand(19260817),srand(time(0)),srand(rand()),srand(rand());
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&xo[i],&yo[i],&m[i]),x+=xo[i],y+=yo[i];
        x/=n,y/=n;
        work();
        return printf("%.3lf %.3lf
    ",ansx,ansy),0;
    }
    
  • 相关阅读:
    性能测试篇 :Jmeter HTTP代理服务器录制压力脚本
    使用JMeter录制手机App脚本
    WEB接口测试之Jmeter接口测试自动化 (二)(数据分离)
    【Python】Python读取文件报错:UnicodeDecodeError: 'gbk' codec can't decode byte 0x99 in position 20: illegal multibyte sequence
    【Python】学习笔记九:面向对象拓展
    【Python】学习笔记七:函数
    【Python】学习笔记五:缩进与选择
    【Python】学习笔记三:序列
    【Python】学习笔记二:基本数据类型
    【Python】学习笔记一:Hello world
  • 原文地址:https://www.cnblogs.com/tlx-blog/p/13899787.html
Copyright © 2011-2022 走看看