目录
A. Lucky?
B. Equal Candies
C. Most Similar Words
D.D. X-Sum
E. Eating Queries
F. Longest Strike
G. White-Black Balanced Subtrees
H. Maximum Crossings (Easy and Hard Version)
暴力模拟
题目意思:六个数字组成的票据,如果票据的前三个数字之和和后三个数字之和是否相等
考虑string读入直接模拟前后即可
void solve()
{
string s; cin>>s;
int ans1=0,ans2=0;
for(int i=0;i<3;i++) ans1+=s[i]-'0';
for(int i=3;s[i];i++) ans2+=s[i]-'0';
if(ans1==ans2) cout<<"YES"<
暴力枚举
题目意思:你可减少每个序列但不能增加求最后相等最少需要减少多少
明显的直接变为最小值是最优的,然后求和做差即可
int a[N];
void solve()
{
cin>>n;
LL ans=0;
int mi=2e9;
for(int i=1;i<=n;i++) cin>>a[i],mi=min(mi,a[i]);
for(int i=1;i<=n;i++){
ans+=a[i]-mi;
}
cout<
数据范围很小直接暴力枚举就好了
题目意思给定你n个长度一样的串,你每次可以把一个串的位置直接变为相邻的字母花费1注意z不能变为a
直接暴力美剧变化做减法即可,如果是能够z->a就需要考虑26-去这个字符
string s[N];
void solve()
{
cin>>n>>m;
int ans=INF;
for(int i=1;i<=n;i++) cin>>s[i];
for(int i=1;i
简单模拟
题目意思:给定你一个二维数组考虑两个斜线X的和的最大值
直接用斜线的状态维护即可i+j和2*n-(i+j)
int a[M][M];
int d[N],ud[N];
void solve()
{
cin>>n>>m;
for(int i=1;i<=2*(n+m);i++) d[i]=0,ud[i]=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
ud[2*n-i+j]+=a[i][j];
d[i+j]+=a[i][j];
}
}
int ans=0,res=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
res=ud[2*n-i+j]+d[i+j]-a[i][j];// 注意重复
ans=max(res,ans);
}
}
cout<
前缀和+二分
题目意思:给定你n个糖和m个询问问你最少吃即可糖可以>=需要甜度
我们发现最少几个大于等于明显的二分提示语句,首先对糖果排序然后前缀和接着就可以直接二分答案了
int a[N];
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+1+n,greater());
for(int i=1;i<=n;i++) a[i]+=a[i-1];
while(m--){
int x; cin>>x;
if(x>a[n]) cout<<-1<>1;
if(a[mid]
双指针
题目意思:给定一个序列,你要求出一个最大的区间[l,r]满足里面的数的在序列当中出现的次数大于等于m要区间的长度最大
首先我们肯定是把满足要求的数放到处理数组里面接着我们要求区间是连续的所以进行排序判断是否是连续的然后双指针来移动判断即可
void solve()
{
cin>>n>>m;
mp.clear();
res.clear();
for(int i=1;i<=n;i++) cin>>a[i],mp[a[i]]++;
for(auto &[k,v]:mp){
if(v>=m) res.emplace_back(k);
}
sort(res.begin(),res.end());
int cnt=res.size();
if(!cnt){
cout<<-1<ans){
ans=len;
r=res[i],l=res[i]-len+1;
}
len=1;
}
}
if(len>ans){
r=res[cnt-1],l=r-len+1;
}
cout<
树的简单运用
题目意思一个树上的节点要么是黑色要么是白色我们看有多少子树的黑白色是一样的
我们明显的可以发现直接使用递归的处理然后把子问题的结果给父节点即可我们可以把白色看成1黑色-1来处理
int dfs(int u)
{
int ans=res[u];
for(auto &k:g[u]){
ans+=dfs(k);
}
if(ans==0) cnt++;
return ans;
}
void solve()
{
cin>>n;
cnt=0;
for(int i=1;i<=n;i++) g[i].clear();
for(int i=2;i<=n;i++){
int x; cin>>x;
g[x].push_back(i);
}
string s; cin>>s;
s=' '+s;
for(int i=1;i<=n;i++){
if(s[i]=='B') res[i]=1;
else res[i]=-1;
}
dfs(1);
cout<
逆序对
题目意思就是两个线段中i到ai有一条边,求最多多少个交点
我们可以发现其实交点的数量就是逆序对的数量可以简单思考一下即可
接着我们可以用树状数组或者是归并排序求逆序对
1.归并算法
int ans;
int a[N],tmp[N];
LL gui_sort(int l,int r)
{
if(l>=r) return 0;
int mid=l+r>>1;
int res=gui_sort(l,mid)+gui_sort(mid+1,r);
int k=0,i=l,j=mid+1;
while(i<=mid&&j<=r){
if(a[i]>n;
for(int i=1;i<=n;i++) cin>>a[i];
cout<
2.树状数组
struct BIT{ int tr[N]; int inline lowbit(int x){ return x&(-x); }; void add(int k,int x){ for(int i=k;i<=n;i+=lowbit(i)) tr[i]+=x; }; int query(int k){ int res=0; for(int i=k;i;i-=lowbit(i)) res+=tr[i]; return res; }; }tree; int a[N]; void solve() { cin>>n; for(int i=1;i<=n;i++) tree.tr[i]=0; for(int i=1;i<=n;i++){ cin>>a[i]; } LL ans=0; for(int i=1;i<=n;i++){ ans+=tree.query(n)-tree.query(a[i]-1); tree.add(a[i],1); } cout<