2024/9/26/27/28
这几天专题和比赛太多了,所以写到一起了。
[ABC351G] Hash on Tree
首先暴力的 \(DP\) 很简单。
然后尝试每次操作在链上修改,看看能不能卡过去。结果写了我 30min 还是被数据卡了。
于是只能去写正解的 \(DDP\)。
先是 131 行的树剖,又是 62 行的线段树维护矩乘。然后在纸上推了推矩乘,胡了个转移方程(我绝对不会说我推错了后去看了题解)。
然后调了 76min 调过了。
[ABC130D] Enough Array
因为下午还有模拟赛,所以果断放弃难题去水 ABC。
一个简单的二分前缀和查找区间个数。
小学不等式一推过掉(我爱水题)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int mod=998244353;
const int maxn=2e5+10;
const int inf=-1e9-7;
int n,k;
int sum[maxn],a[maxn],ans;
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
// #else
// freopen("defense.in","r",stdin);
// freopen("defense.out","w",stdout);
#endif
cin>>n>>k;
for(int i=1;i<=n;i++)a[i]=read(),sum[i]=sum[i-1]+a[i];
for(int i=1;i<=n;i++)
{
int pos=lower_bound(sum+i,sum+n+1,sum[i-1]+k)-sum;
ans+=(n-pos+1);
}
cout<<ans;
return 0;
}
[ABC127D] Integer Cards
首先贪心选择最小值更新。
发现直接更新的话复杂度巨大。
于是加上小技巧,把操作离线后排个序再更新保证每个元素的更新次数。
然后就过了。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int mod=998244353;
const int maxn=2e5+10;
const int inf=-1e9-7;
int n,m;
struct no
{
int b,c;
inline friend bool operator < (no x,no y)
{
return x.c>y.c;
}
}a[maxn];
priority_queue<int,vector<int>,greater<int> > q;
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
// #else
// freopen("defense.in","r",stdin);
// freopen("defense.out","w",stdout);
#endif
cin>>n>>m;
for(int i=1;i<=n;i++)q.push(read());
for(int i=1;i<=m;i++)a[i]={read(),read()};
sort(a+1,a+m+1);
for(int i=1;i<=m;i++)
{
while(a[i].b)
{
int u=q.top();
if(u>=a[i].c)break;
q.pop();
u=a[i].c;
q.push(u);
a[i].b--;
}
}
int ans=0;
while(!q.empty())ans+=q.top(),q.pop();
cout<<ans;
return 0;
}
[ABC122C] GeT AC
这不一眼前缀和?
写完以后发现样例假了。
但是简单思考发现只有当 AC
两个字符分别在 \(l-1\) 和 \(l\) 的位置上的时候才会出错。
于是加上特判,轻松过掉。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int mod=998244353;
const int maxn=2e5+10;
const int inf=-1e9-7;
int n,Q;
char s[maxn];
int sum[maxn];
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
// #else
// freopen("defense.in","r",stdin);
// freopen("defense.out","w",stdout);
#endif
cin>>n>>Q;
scanf("%s",s+1);
for(int i=1;i<=n;i++)
{
if(s[i]=='C'&&s[i-1]=='A')sum[i]=sum[i-2]+1;
else sum[i]=sum[i-1];
}
while(Q--)
{
int l=read(),r=read();
int ans=sum[r]-sum[l-1];
if(s[l-1]=='A'&&s[l]=='C')ans--;
printf("%lld\n",ans);
}
return 0;
}
P6021 洪水
看着排行榜打算回来继续 DDP。
和第一题比较类似的常规 DDP。
写了 50min,开始调。
调到吃完饭,调到睡午觉。
然后发现:
晕倒了。
[ABC136E] Max GCD
考炸了,回来水题和题解。
题目翻译没看懂,上 AT 发现 deepl 都比翻译好。
想了一会发现一个必要条件,于是可以通过反推验证的方法找到所有可能解。
对于验证的话发现可以按照模数排序以后双指针贪心搞。
写完以后发现错了,接下来是最唐的时刻:
唐1
验证模数取了个常量。
唐2
数组大小和模数大小搞反了。
唐3
优先级搞错了。
终于过了:
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int mod=1e9+7;
const int maxn=3e3+10;
const int inf=1e9+7;
int n,k,a[maxn],sum,b[maxn];
bool ch(int x)
{
for(int i=1;i<=n;i++)b[i]=a[i]%mod;
sort(b+1,b+n+1);
int l=1,r=n,res=0;
while(l<=r)
{
for(;b[l]&&l<=r;l++);
for(;b[r]&&l<=r;r--);
int mi=min(b[l]%x,x-b[r]%x);
b[l]-=mi;b[r]+=mi;
res+=mi;
}
return res<=k;
}
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
// #else
// freopen("Oros.in","r",stdin);
// freopen("Oros.out","w",stdout);
#endif
cin>>n>>k;
for(int i=1;i<=n;i++)a[i]=read(),sum+=a[i];
int ans=1;
for(int i=1;i<=sqrt(sum*1.0);i++)
{
if(sum%i)continue;
int j=sum/i;
ans=max({ans,(ch(i)?i:-inf),(ch(j)?j:-inf)});
}
cout<<ans;
return 0;
}
[ARC145C] Split and Maximize
小清新结论题。
首先瞪眼可知使结果最大的构造方案。
然后考虑使结果不变的情况下如何产生不同的方案数。
加法和乘法原理分别讨论一下,然后就推到了卡特兰数,结果甚至不需要求组合数,边乘边取余即可。
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int mod=998244353;
const int maxn=4e5+10;
const int inf=1e9+7;
int n;
int qw(int x,int y)
{
int ans=1;
while(y)
{
if(y&1)ans=ans*x%mod;
x=x*x%mod;
y>>=1;
}
return ans;
}
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
// #else
// freopen("Boreas.in","r",stdin);
// freopen("Boreas.out","w",stdout);
#endif
cin>>n;
int ans=qw(2,n);
for(int i=n+2;i<=2*n;i++)ans=ans*i%mod;
cout<<ans;
return 0;
}
[ABC026D] 高橋君ボール1号
一眼觉得函数不单增好像只能模拟退火(我也不会),两眼发现根据题目要求我们只需要找到一组可行解,所以二分即使不能找到所有解,最终也一定能停留到某一个正确的解,因此可行。
写完以后发现样例误差很大,怎么调都调不过来,一怒之下直接交,然后就过了?然后发现题目是SPJ
点击查看代码
#include <bits/stdc++.h>
#define int long long
#define pi 3.141592653589793
using namespace std;
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int mod=998244353;
const int maxn=4e5+10;
const int inf=1e10+7;
double a,b,c;
bool ch(double x)
{
return a*x+b*sin(c*x*pi)>100;
}
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
// #else
// freopen("Boreas.in","r",stdin);
// freopen("Boreas.out","w",stdout);
#endif
cin>>a>>b>>c;
double l=1,r=1e9+7;
for(int i=1;i<=6e6;i++)
{
double mid=(l+r)/2.00;
if(ch(mid))r=mid;
else l=mid;
}
printf("%.10lf",l);
return 0;
}
[ABC204D]Cooking
比较熟悉的套路。
把题意经过两次转化以后可以得到一个 01 背包,然后我们就直接做。
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int mod=998244353;
const int maxn=4e5+10;
const int inf=1e9+7;
int n,a[maxn],sum;
int dp[120][200000];
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
// #else
// freopen("Boreas.in","r",stdin);
// freopen("Boreas.out","w",stdout);
#endif
cin>>n;
for(int i=1;i<=n;i++)a[i]=read(),sum+=a[i];
for(int i=1;i<=n;i++)
{
for(int j=sum/2;j>=a[i];j--)
{
dp[i][j]=max(dp[i-1][j],dp[i-1][j-a[i]]+a[i]);
}
}
cout<<sum-dp[n][sum/2];
return 0;
}
[ABC322C] Festival
本来是来看 D 的,但是不会,所以去看 C 了。发现可以水。
一个不加任何掩饰的二分。
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int mod=998244353;
const int maxn=4e5+10;
const int inf=1e9+7;
int n,m,a[maxn];
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
// #else
// freopen("Boreas.in","r",stdin);
// freopen("Boreas.out","w",stdout);
#endif
cin>>n>>m;
for(int i=1;i<=m;i++)a[i]=read();
for(int i=1;i<=n;i++)
{
int pos=a[lower_bound(a+1,a+m+1,i)-a];
cout<<pos-i<<endl;
}
return 0;
}
[EC Final 2021] DFS Order
看见 Final 还以为是什么难题,然后简单想了一下发现只需要求解每个节点的深度和子树大小即可。
一开始因为 memset
T 了一发。
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int mod=1e9+7;
const int maxn=2e5+10;
const int inf=1e9+7;
int n,dep[maxn],siz[maxn];
vector<int> G[maxn];
void dfs(int x,int fa)
{
dep[x]=dep[fa]+1;
siz[x]=1;
for(auto y:G[x])
{
if(y==fa)continue;
dfs(y,x);
siz[x]+=siz[y];
}
}
void Main()
{
n=read();
for(int i=1;i<=n;i++)G[i].clear();
for(int i=1;i<=n;i++)dep[i]=siz[i]=0;
for(int i=1;i<n;i++)
{
int x=read(),y=read();
G[x].push_back(y);
G[y].push_back(x);
}
dfs(1,0);
for(int i=1;i<=n;i++)
{
printf("%lld %lld\n",dep[i],n-siz[i]+1);
}
}
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
// #else
// freopen("Zephyros.in","r",stdin);
// freopen("Zephyros.out","w",stdout);
#endif
int T=read();
while(T--)Main();
return 0;
}
[ARC115A] Two Choices
一开始盲目 set
发现样例过不去,以为是代码问题,但是在纸上推了推发现没问题。再看一眼题发现题读错了(我是废物
根据题目条件可以很好地根据 \(0\) 的奇偶性找到一个规律,然后用个桶统计一下就行了。
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int mod=1e9+7;
const int maxn=2e5+10;
const int inf=1e9+7;
int n,m;
int a[maxn][25];
int b[maxn];
multiset<int> se;
int f[maxn*25];
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
// #else
// freopen("brike.in","r",stdin);
// freopen("brike.out","w",stdout);
#endif
cin>>n>>m;
for(int i=1;i<=n;i++)
{
int sum=0;
for(int j=1;j<=m;j++)
{
char c;cin>>c;
b[i]+=(c=='0');
}
f[b[i]%2]++;
}
cout<<f[0]*f[1]<<endl;
return 0;
}