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\n";
        else cout<<"NO\n";
    }
    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<<"\n";
    }
    return 0;
}

T6 349B Color the Fence

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

找到 $a_1\sim 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.偶数个:从第一个开始 \(2\quad 1\quad 2\quad 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\n";
            FOR(i,1,n) cout<<"1 ";
            cout<<"\n";
	}
	else if(n%2==0)
	{
	    cout<<"2\n";
            FOR(i,1,n/2) cout<<"2 1 ";
            cout<<"\n";
	}
	else if(flag)
	{
            cout<<2<<"\n";
	    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<<"\n";
	}
	else 
	{
            cout<<"3\n";
            FOR(i,1,n-1) cout<<i%2+1<<" ";
            cout<<"3\n";
	}
    }
    return 0;
}

T8 1253C Sweets Eating

https://www.luogu.com.cn/problem/CF1253C
预处理前缀和,从 \(1\)\(n\) 枚举,加上 \(a_i\),如果 \(i\geq 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('\n');}
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\) 从大到小相同的二进制位舍去,到第一个不同的位,则答案是 该位代表的值 \(\times 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('\n');}
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('\n');}
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('\n');}
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;
}

待更。

还有

未写

posted @ 2020-07-28 16:09  沸-腾-鱼  阅读(337)  评论(0编辑  收藏  举报