CF 1500-2000 DP&贪心
前言:太逊啦,都人均在切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;
}
T7 1328D Carousel
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;
}
待更。
还有
无
未写