zoukankan      html  css  js  c++  java
  • CF 1500-2000 DP&贪心

    Link

    前言:太逊啦,都人均在切3000+的题,就我……

    刚刚开始做……要持续更个一个月吧qwq

    T1 550A Two Substrings

    https://www.luogu.com.cn/problem/CF550A
    根据题意暴力判断,先判BA,判到打标记,再判AB

    int len=strlen(s+1);
    FOR(i,1,len-1)
    {
        if(s[i]=='A'&&s[i+1]=='B'&&flag&&!vis[i]) 
        {
            cout<<"YES";
            return 0;
        }
        if(s[i]=='B'&&s[i+1]=='A'&&!flag) flag=1,vis[i+1]=1;
    }
    

    然后,就会获得RE on 7的好成绩

    再看数据范围,嗯,翻译翻错了。

    再交了一发,又错了,看了下数据,ABBA就能把我卡掉,所以反着再判一遍,就过了qwq。

    #include<iostream>
    #include<cstdio>
    #include<string.h>
    using namespace std;
    #define FOR(i,a,b) for(int i=a;i<=b;i++)
    #define REP(i,a,b) for(int i=a;i>=b;i--)
    char s[100005];
    bool vis[100005],flag;
    int main()
    {
        scanf("%s",s+1);
        int len=strlen(s+1);
        FOR(i,1,len-1)
        {
            if(s[i]=='A'&&s[i+1]=='B'&&flag&&!vis[i]) 
            {
                cout<<"YES";
                return 0;
            }
            if(s[i]=='B'&&s[i+1]=='A'&&!flag) flag=1,vis[i+1]=1;
        }
        flag=0;
        memset(vis,0,sizeof vis);
        FOR(i,1,len-1)
        {
            if(s[i]=='B'&&s[i+1]=='A'&&flag&&!vis[i]) 
            {
                cout<<"YES";
                return 0;
            }
            if(s[i]=='A'&&s[i+1]=='B'&&!flag) flag=1,vis[i+1]=1;
        }
        cout<<"NO";
        return 0;
    }
    

    T2 545C Woodcutters

    https://www.luogu.com.cn/problem/CF545C
    简单贪心qwq。

    第一棵树向左,最后一棵树向右。

    中间的能往左就往左,剩下能向右就向右,否则就不砍。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define FOR(i,a,b) for(int i=a;i<=b;i++)
    #define REP(i,a,b) for(int i=a;i>=b;i--)
    inline int read()
    {
        int f=1,x=0;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return f*x;
    }
    int n,ans=2;
    struct node
    {
        int x,h;
    }a[100005];
    int main()
    {
        scanf("%d",&n);
        if(n==1)
        {
            cout<<1;
            return 0;
        }
        FOR(i,1,n) a[i].x=read(),a[i].h=read();
        FOR(i,2,n-1)
        {
            if((a[i].x-a[i-1].x)>a[i].h) 
            {
                ans++;
                continue;
            }
            if((a[i].x+a[i].h)>=a[i+1].x) continue;
            ans++;
            a[i].x+=a[i].h;
        }
        cout<<ans;
        return 0;
    }
    

    T3 1366A Linova and Kingdom

    https://www.luogu.com.cn/problem/CF1336A
    树形DP的结论题。

    答案就是前 (K)(dep_i-siz_i) 之和。感谢wyy神仙提醒

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define int long long
    #define FOR(i,a,b) for(int i=a;i<=b;i++)
    #define REP(i,a,b) for(int i=a;i>=b;i--)
    int n,k,f[200005];
    bool cmp(int x,int y)
    {
        return x>y;
    }
    int fir[200005],tot;
    struct edge
    {
        int nxt,to;
    }e[200005<<1];
    void add(int u,int v)
    {
        e[++tot]={fir[u],v};fir[u]=tot;
    }
    struct node
    {
        int u,v;
    }a[200005];
    int dep[200005],siz[200005];
    void DFS(int u,int dad)
    {
        dep[u]=dep[dad]+1;
        siz[u]=1;
        for(int i=fir[u];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(v==dad) continue;
            DFS(v,u);
            siz[u]+=siz[v];
        }
    }
    signed main()
    {
        scanf("%lld%lld",&n,&k);
        FOR(i,1,n-1)
            scanf("%lld%lld",&a[i].u,&a[i].v),add(a[i].u,a[i].v),add(a[i].v,a[i].u);
        dep[0]=0;siz[0]=0;
        DFS(1,0);
        FOR(i,1,n) f[i]=dep[i]-siz[i];
        sort(f+1,f+1+n,cmp);
        int ans=0;
        FOR(i,1,k) ans+=f[i];
        cout<<ans;
        return 0;
    }
    

    T4 1304C Air Conditioner

    https://www.luogu.com.cn/problem/CF1304C
    按顾客到达的顺序来处理。维护温度可能的区间 ([l, r])。从顾客 ({i-1})(i) 时,过去的时间 (dis = t_i - t_{i - 1})
    ,温度可能的区间 ([l', r'] = [l - dis, r + dis])

    为了满足顾客需求,再取相交的。如果集合为空,输出(NO)

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define FOR(i,a,b) for(int i=a;i<=b;i++)
    #define REP(i,a,b) for(int i=a;i>=b;i--)
    int t,n,m;
    struct node
    {
        int l,h,t;
    }a[105];
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&m);
            FOR(i,1,n)
                scanf("%d%d%d",&a[i].t,&a[i].l,&a[i].h);
            int L=m,R=m;
            bool flag=1;
            FOR(i,1,n)
            {
                int dis=a[i].t-a[i-1].t;
                L-=dis;
                R+=dis;
                L=max(L,a[i].l);
                R=min(R,a[i].h);
                if(L>R)
                {
                    flag=0;
                    break;
                }
            }
            if(flag) cout<<"YES
    ";
            else cout<<"NO
    ";
        }
        return 0;
    }
    

    T5 1373D Maximum Sum on Even Positions

    https://www.luogu.com.cn/problem/CF1373D
    如果 (i\%2=1)

    ans+=a[i];
    NOW=max(0LL,NOW+a[i-1]-a[i]);
    MAX=max(MAX,NOW);
    

    如果 (i\%2=0)

    now=max(0LL,now+a[i]-a[i-1]);
    MAX=max(MAX,now);
    

    最后输出 ans+MAX

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define int long long
    #define FOR(i,a,b) for(int i=a;i<=b;i++)
    #define REP(i,a,b) for(int i=a;i>=b;i--)
    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-48;ch=getchar();}
        return x*f;
    }
    int t;
    signed main()
    {
        scanf("%lld",&t);
        while(t--)
        {
            int n,a[200005];
            scanf("%lld",&n);
            int ans=0,now=0,MAX=0,NOW=0;
            FOR(i,1,n) 
            {
                a[i]=read();
                if((i&1)) 
                {
                    ans+=a[i];
                    NOW=max(0LL,NOW+a[i-1]-a[i]);
                    MAX=max(MAX,NOW);
    			}
                else 
                {
                    now=max(0LL,now+a[i]-a[i-1]);
                    MAX=max(MAX,now);
                }
            }
            cout<<ans+MAX<<"
    ";
        }
        return 0;
    }
    

    T6 349B Color the Fence

    https://www.luogu.com.cn/problem/CF349B
    贪心qwq

    找到 $a_1sim a_9 $ 中的最小值,用最小值去求出答案的长度,然后由高至低不断去替换答案中的每一位,最后即可得到正确答案

    #include<iostream>
    #include<cstdio>
    #include<vector>
    using namespace std;
    #define FOR(i,a,b) for(int i=a;i<=b;i++)
    #define REP(i,a,b) for(int i=a;i>=b;i--)
    int v,a[10],MIN=0x3f3f3f3f,id;
    vector<int>ans;
    int main()
    {
        scanf("%d",&v);
        FOR(i,1,9) 
        {
    	scanf("%d",&a[i]);	
    	if(a[i]<=MIN) MIN=a[i],id=i;
        }
        if(MIN>v)
        {
    	cout<<"-1";
    	return 0;
        }
        while(1)
        {
     	if(v<MIN) break;
    	ans.push_back(id);
    	v-=MIN;
        }
        FOR(i,0,ans.size()-1)
        {
    	bool flag=1;
    	REP(j,9,id+1)
    	{
                if(a[j]-MIN<=v)
    	    {
    		ans[i]=j;
    	 	v-=a[j]-MIN;
    		flag=0;
    		break;
    	    }
    	} 
    	if(flag) break;
        }
        FOR(i,0,ans.size()-1) cout<<ans[i];
        return 0;
    }
    

    https://www.luogu.com.cn/problem/CF1328D
    1.所有数都一样:全都染 (1),用 (1) 种颜色。

    2.偶数个:从第一个开始 (2quad 1quad 2quad 1……2 quad1),由于是一个环,首和尾必须不一样,用 (2) 种颜色。

    3.奇数个,有两个相邻数的相同:奇数个就因为首尾哪样染的话会相同,此时有两个相邻的数相同,可以安排他们相同,使得可以用上种方法。

    4.奇数个,相邻的数都不相同:没办法 (2) 个数了,任意两个相邻的数都不能相同至少 (3) 个数,先按偶数个那么染,等到最后一个数就染成 (3)

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define FOR(i,a,b) for(int i=a;i<=b;i++)
    #define REP(i,a,b) for(int i=a;i>=b;i--)
    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-48;ch=getchar();}
        return x*f;
    }
    int a[200005],t;
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
    	int n;
    	bool flag=0;
            bool flag1=1;
    	scanf("%d",&n);
    	FOR(i,1,n) a[i]=read();
    	FOR(i,1,n)
    	{
                int x=i-1;
    	    if(x==0) x=n;
    	    if(a[i]==a[x]) flag=1;
    	    else flag1=0;
    	}
    	if(flag1)
    	{
    	    cout<<"1
    ";
                FOR(i,1,n) cout<<"1 ";
                cout<<"
    ";
    	}
    	else if(n%2==0)
    	{
    	    cout<<"2
    ";
                FOR(i,1,n/2) cout<<"2 1 ";
                cout<<"
    ";
    	}
    	else if(flag)
    	{
                cout<<2<<"
    ";
    	    flag=0;
                FOR(i,1,n)
    	    {
    	        int x=i-1;
    		if(x==0) x=n;
    		if(flag) cout<<2-(i%2)<<" ";
                    else if(a[i]==a[x]) 
                    {
                        cout<<2-(i%2)<<" ";
                        flag=1;
                    }
                    else cout<<i%2+1<<" ";
    	    }
    	    cout<<"
    ";
    	}
    	else 
    	{
                cout<<"3
    ";
                FOR(i,1,n-1) cout<<i%2+1<<" ";
                cout<<"3
    ";
    	}
        }
        return 0;
    }
    

    T8 1253C Sweets Eating

    https://www.luogu.com.cn/problem/CF1253C
    预处理前缀和,从 (1)(n) 枚举,加上 (a_i),如果 (igeq m) 就加上前缀和。

    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define int long long
    #define FOR(i,a,b) for(int i=a;i<=b;i++)
    #define REP(i,a,b) for(int i=a;i>=b;i--)
    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-48;ch=getchar();}
        return x*f;
    }
    int n,m,a[200005],sum[200005];
    signed main()
    {
        n=read();m=read();
        FOR(i,1,n) a[i]=read();
        sort(a+1,a+1+n);
        FOR(i,m,n) sum[i]=sum[i-m]+a[i-m];
        int ANS=0;
        FOR(i,1,n)
        {
            ANS+=a[i];
            if(i>m) ANS+=sum[i];
            cout<<ANS<<" ";
        }
        return 0;
    }
    

    T9 1389C Good String

    https://www.luogu.com.cn/problem/CF1389C
    容易发现满足条件的字符串只会是 (aaaaaaaa...) 或者 (abababab...) 类型。

    那么就分别计算两种情况。前一种方法显然。

    由于题目告诉我们只可能是 (0-9) 之间的数字,那么可能存在的 (abababab...) 序列数只会有 (90) 种。对每种进行计算即可。

    #include<iostream>
    #include<cstdio>
    #include<string.h>
    using namespace std;
    #define FOR(i,a,b) for(int i=a;i<=b;i++)
    #define REP(i,a,b) for(int i=a;i>=b;i--)
    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-48;ch=getchar();}
        return x*f;
    }
    inline void write(int x)
    {
        if(x<0) putchar('-'),write(-x);
        else{if(x>9)write(x/10);putchar('0'+x%10);}
    }
    inline void writeputs(int x){write(x),putchar('
    ');}
    inline void writeputchar(int x){write(x),putchar(' ');}
    int t,n,num[15],dp[10][10],ANS;
    char s[200005];
    int main()
    {
        t=read();
        while(t--)
        {
            memset(num,0,sizeof num);
            memset(dp,0,sizeof dp);
            scanf("%s",s+1);
            int len=strlen(s+1);
            ANS=0;
            FOR(i,1,len) num[s[i]-'0']++;
            FOR(i,1,len) 
            {
                int ch=s[i]-'0';
                FOR(j,0,9)
                {
                    if(j==ch) continue;
                    if(dp[j][ch]%2!=0) dp[j][ch]++;
                    if(dp[ch][j]%2==0) dp[ch][j]++;
                }
            }
            FOR(i,0,9) ANS=max(ANS,num[i]);
            FOR(i,0,9)
                FOR(j,0,9)
                    if(i!=j)
                        ANS=max(ANS,dp[i][j]/2*2);
            writeputs(len-ANS);
        }
        return 0;
    }
    

    T10 276D Little Girl and Maximum XOR

    https://www.luogu.com.cn/problem/CF276D
    我们把 (a,b) 从大到小相同的二进制位舍去,到第一个不同的位,则答案是 该位代表的值 ( imes 2-1)(a=b) 时是 (0)

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define FOR(i,a,b) for(int i=a;i<=b;i++)
    #define REP(i,a,b) for(int i=a;i>=b;i--)
    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-48;ch=getchar();}
        return x*f;
    }
    inline void write(int x)
    {
        if(x<0) putchar('-'),write(-x);
        else{if(x>9)write(x/10);putchar('0'+x%10);}
    }
    inline void writeputs(int x){write(x),putchar('
    ');}
    inline void writeputchar(int x){write(x),putchar(' ');}
    inline int f(int x)
    {
        int res=0;
        while(x) x/=2,res++;
        return res;
    }
    inline int pow(int x,int y)
    {
        int res=1;
        while(y)
        {
        	if(y&1) res=res*x;
        	y>>=1;
        	x=x*x;
        }
        return res;
    }
    int ans=-1;
    int l,r,t;
    int main()
    {
        l=read(),r=read();
        l^=r;
        FOR(i,0,59) if(l>>i&1) ans=i;
        write(((int)(1)<<ans+1)-1);
        return 0;
    }
    

    T11 1207C Gas Pipeline

    https://www.luogu.com.cn/problem/CF1207C
    (dp_{i,0}) 为到达 (i) 时高度为 (1) 的最小答案,(dp_{i,1}) 为到达 (i) 时高度为 (2) 的最小答案


    • (dp_{i,0}: 1e15)
      (dp_{i,1}:)上一个位置下来再上来和直接平行取 (min)
    • 不是
      (dp_{i,0}:)上一个位置下来和直接平行过来取 (min)
      (dp_{i,1}:)上来和直接平行过来取 (min)
    #include<iostream>
    #include<cstdio>
    #include<string.h>
    using namespace std;
    #define int long long
    #define FOR(i,a,b) for(int i=a;i<=b;i++)
    #define REP(i,a,b) for(int i=a;i>=b;i--)
    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-48;ch=getchar();}
        return x*f;
    }
    inline void write(int x)
    {
        if(x<0) putchar('-'),write(-x);
        else{if(x>9)write(x/10);putchar('0'+x%10);}
    }
    inline void writeputs(int x){write(x),putchar('
    ');}
    inline void writeputchar(int x){write(x),putchar(' ');}
    int t,n,a,b,dp[200005][5];
    signed main()
    {
        t=read();
        while(t--)
        {
            n=read(),a=read(),b=read();
            char s[200005];
            cin>>s;
            memset(dp,0,sizeof dp);
            dp[0][1]=1e15;dp[0][0]=a+b;
            FOR(i,1,n)
            {
                if(s[i]=='1')
                {
                    dp[i][0]=1e15;
                    dp[i][1]=min(dp[i-1][0]+a+b+b+a,dp[i-1][1]+b+b+a);
                }
                if(s[i]=='0')
                {
                    dp[i][0]=min(dp[i-1][0]+a+b,dp[i-1][1]+a+a+b+b);
                    dp[i][1]=min(dp[i-1][0]+a+a+b,dp[i-1][1]+a+b+b);
                }
            }
            writeputs(dp[n-1][0]+b);
        }
        return 0;
    }
    

    T12 1051C Vasya and Multisets

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

    因为出现 (1) 次情况时候是一定是不错的,与答案有关,出现 (2) 次情况时候只有 (2,0)(1,1) ,与答案无关,所以跟出现次数 (geq 3) 次情况时候是与答案有关的,可以分为 (1,n-1)
    具体看代码吧

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define FOR(i,a,b) for(int i=a;i<=b;i++)
    #define REP(i,a,b) for(int i=a;i>=b;i--)
    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-48;ch=getchar();}
        return x*f;
    }
    inline void write(int x)
    {
        if(x<0) putchar('-'),write(-x);
        else{if(x>9)write(x/10);putchar('0'+x%10);}
    }
    inline void writeputs(int x){write(x),putchar('
    ');}
    inline void writeputchar(int x){write(x),putchar(' ');}
    int n,a[105],tong[105],ANS,ans;
    bool flag;
    int main()
    {
        n=read();
        FOR(i,1,n) a[i]=read(),tong[a[i]]++;
        FOR(i,1,100)
        {
            if(tong[i]==1) ANS++;
            if(tong[i]>=3) ans++;
        }
        if(ans>=1&&ANS%2==1) flag=1,puts("YES");
        else if(ANS%2==0) puts("YES");
        else 
        {
            puts("NO");
            return 0;
        }
        int num=0;
        if(ANS%2==0)
        {
            FOR(i,1,n) 
            {
                if(tong[a[i]]==1&&num<ANS/2) putchar('A'),num++;
                else putchar('B');
            }
            return 0;
        }
        if(ANS%2==1)
        {
            FOR(i,1,n)
            {
                if(tong[a[i]]==1&&num<=ANS/2-1) putchar('A'),num++;
                else if(tong[a[i]]==1&&num>=ANS/2) putchar('B');
                else if(tong[a[i]]>=3&&flag) putchar('A'),flag=0;
                else putchar('B');
            }
        }
        return 0;
    }
    

    待更。

    还有

    未写

  • 相关阅读:
    【BZOJ-1060】时态同步 树形DP (DFS爆搜)
    【BZOJ-1468】Tree 树分治
    【BZOJ-1097】旅游景点atr SPFA + 状压DP
    【BZOJ-3876】支线剧情 有上下界的网络流(有下界有源有汇最小费用流)
    【BZOJ-2502】清理雪道 有上下界的网络流(有下界的最小流)
    【BZOJ-2055】80人环游世界 上下界费用流 (无源无汇最小费用流)
    【BZOJ-3275&3158】Number&千钧一发 最小割
    【BZOJ-4562】食物链 记忆化搜索(拓扑序 + DP)
    【BZOJ-1367】sequence 可并堆+中位数
    【BZOJ-1455】罗马游戏 可并堆 (左偏树)
  • 原文地址:https://www.cnblogs.com/F-T-Y/p/1500-2000-DP-Greedy.html
Copyright © 2011-2022 走看看