zoukankan      html  css  js  c++  java
  • 7.15

    7.15 dp专题

    T1.sum 小Z爱求和

    https://www.luogu.com.cn/problem/T138967

    无脑暴力骗20...

    正解

    n^2 个元素,挨个统计是 O( n^2 ) ,所以统计每个点的贡献 复杂度降到O(n)

    对于每个点,他可能贡献的区间是 L= pre(k-1) 前跳 k-1 个前驱 R=nxt ———— L=pre R=nxt(k-1) 后跳 k-1 个后继

    然后链表维护——链表比较好维护删除,不好维护插入,所以我们先按把原序列搞成链表,然后从小到大(大到小同理,reverse一下即可) 考虑

    总复杂度 O(n*k)

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    inline int read() {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f; 
    }
    typedef long long LL;
    const LL mod = 998244353;
    const int N = 1e6+10;
    int n,k,a[N];
    int pre[N],nxt[N],pos[N];
    LL ans;
    bool cmp(int i,int j){
        return a[i]<a[j];
    }
    void calc(){
        for(int i=1;i<=n;i++) pre[i]=i-1,nxt[i]=i+1;
        for(int i=1;i<=n;i++){
            int c=1,x=pos[i],L=pos[i],R=pos[i];
            for(;c<k;c++) 
                if(pre[L]) L=pre[L]; 
                else break;
            for(;c<k;c++)
                if(nxt[R]!=n+1) R=nxt[R];
                else break;
            if(c==k){
                while(L<=x){
                    if(R==n+1)break;
                    ans+=a[x]*1LL*(nxt[R]-R)%mod*1LL*(L-pre[L])%mod;
                    ans%=mod;
                    L=nxt[L];R=nxt[R];
                }
            }
            pre[nxt[x]]=pre[x];
            nxt[pre[x]]=nxt[x];
        }
    }
    
    int main(){
        n=read();k=read();
        for(int i=1;i<=n;i++) a[i]=read();
        for(int i=1;i<=n;i++) pos[i]=i;
        sort(pos+1,pos+1+n,cmp);
        calc();
        reverse(pos+1,pos+1+n);
        calc();
        printf("%lld
    ",ans);
        return 0;
    }
    

    T2.prison 关押罪犯

    https://www.luogu.com.cn/problem/T138969

    myself

    这个当时只能想到贪心。。。然后没搞出反例,就...

    好吧骗了70 so lucky

    然后这个显然贪心是不正确的,可能有的人在前面的组不是最优

    人生第一次打出状压不容易。。。没满也值得纪念,放这待着吧

        for(int i=1,x,y;i<=m;i++) {
            x=read(),y=read();
            s[x]|=(1<<(y-1));
            s[y]|=(1<<(x-1));
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=ans;j++){
                if((f[j]&(1<<(i-1)))==0){
                    vis[i]=1;
                    f[j]|=s[i];
                    break;
                }else{
                    if(num[j]<k){
                        vis[i]=1;f[j]|=s[i];num[j]++;
                        break;
                    }
                }
            }
            if(!vis[i]){
                ans++;f[ans]|=s[i];vis[i]=1;
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
    

    正解!!!

    先预处理 ok[ ]表示此状态有矛盾的能不能小于 k 个人

    然后状压枚举子集,转移也很好想 f[s]=min(f[s],f[s-ss]+1); 把子集分出来一组,然后组数 +1 ,原来状态减去这个子集

    #include <cstdio>
    #include <iostream>
    using namespace std;
    inline int read() {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f; 
    }
    bool ok[1<<17],g[17][17];
    int f[1<<17],n,m,k,tmp;
    int main(){
        n=read();m=read();k=read();
        for(int i=1,x,y;i<=m;i++){
            x=read()-1;y=read()-1;
            g[x][y]=g[y][x]=1;
        }
        for(int s=0;s<(1<<n);s++){
            for(int i=0;i<n;i++){
                if((s>>i)&1){
                    for(int j=i+1;j<n;j++){
                        if((s>>j)&1)
                            if(g[i][j])
                                tmp++;
                    }
                }
            }
            if(tmp<=k)ok[s]=1;
            tmp=0;
        }
        for(int s=1;s<(1<<n);s++){
            f[s]=n;//取min用的,先赋个最大值
            for(int ss=s;ss>0;ss=(ss-1)&s){
                if(ok[ss])
                    f[s]=min(f[s],f[s-ss]+1);
            }
        }    
        printf("%d
    ",f[(1<<n)-1]);
        return 0;
    }
    

    T3maze

    https://www.luogu.com.cn/problem/T138970

    补卡特兰数:写到组合数学里了https://www.cnblogs.com/liukx/p/13323828.html

    LGV定理

    LGV定理用于解决路径不相交问题。

    详见贾队博客和wiki

    https://www.luogu.com.cn/blog/jzp1115/lgv-ding-li

    ans=Calculate(2,1,n,m-1)Calculate(1,2,n-1,m)-Calculate(2,1,n-1,m)Calculate(1,2,n,m-1);

                绿到绿 * 红到红 (同时走显然没相交)  -     绿到红 * 红到绿
    
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #define M 2020
    #define p 1000000007
    using namespace std;
    int n,m;
    char map[M][M];
    long long f[M][M];
    long long Calculate(int x1,int y1,int x2,int y2){
    	int i,j;
    	if(map[x1][y1]=='1')return 0;
    	memset(f,0,sizeof f);
    	f[x1][y1]=1;
    	for(i=x1;i<=x2;i++)
    		for(j=y1;j<=y2;j++){
    			if(map[i][j]=='1')continue;
    			(f[i][j]+=f[i-1][j]+f[i][j-1])%=p;
    		}
    	return f[x2][y2];
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    		scanf("%s",map[i]+1);
    	long long ans=Calculate(2,1,n,m-1)*Calculate(1,2,n-1,m)-Calculate(2,1,n-1,m)*Calculate(1,2,n,m-1);
        printf("%lld
    ",(ans%p+p)%p);
    	return 0;
    }
  • 相关阅读:
    Method总结
    使用CSS的五种方式
    debug js code
    Overload
    fiddler模拟弱网测试
    POJ 1753 Flip Game (IDA*)
    UVA 11400 Lighting System Design(照明系统设计)(dp)
    UVA 12563 Jin Ge Jin Qu hao(劲歌金曲)(01背包+滚动数组)
    UVA 116 Unidirectional TSP (单向TSP)(dp多段图的最短路)
    UVA 1151 Buy or Build (买还是建)(并查集+二进制枚举子集)
  • 原文地址:https://www.cnblogs.com/liukx/p/13324480.html
Copyright © 2011-2022 走看看