PS: DDD有空再补,题目还没看呢QAQ
Solution
A
可以发现答案有单调性,即如果高度为hhh的房子可以盖出,则高度小于hhh的房子显然可以盖出。
于是我们果断二分。对于目前的高度hhh,我们算出A,BA,BA,B材料总共缺少的数量,然后再与ccc一比即可得到二分的值是否可行。
时间复杂度O(log2109)O(log_2{10^9})O(log2109)。
B
可以发现,满足要求的序列是两个差为kkk交互出现的序列,并且长度是偶数。
于是,我们直接枚举交替出现的这两个数中的一个,另一个也可以求出;然后直接求出对于这两个数形成的序列的最大和即可。注意特判k=0k=0k=0的情况。
另外,无合法序列输出的是NONONO而不是−1-1−1,导致本蒟蒻WA\color{red} \text{WA}WA了好多次 QAQ。
C
比较擅长的数学题,奇迹般地222分钟切掉了
首先,推一推式子。假设这两个数分别是am,bmam,bmam,bm,其中mmm为这两个数的最大公约数;显然a⊥ba⊥ba⊥b(aaa与bbb互质)且a,ba,ba,b均为自然数。
带入,得
x+y+gcd(x,y)=lcm(x,y)x+y+gcd(x,y)=lcm(x,y)x+y+gcd(x,y)=lcm(x,y)
am+bm+m=abmam+bm+m=abmam+bm+m=abm
m(a+b+1)=mabm(a+b+1)=mabm(a+b+1)=mab
a+b+1=aba+b+1=aba+b+1=ab
ab−a−b−1=0ab-a-b-1=0ab−a−b−1=0
ab−a−b+1=2ab-a-b+1=2ab−a−b+1=2
(a−1)(b−1)=2(a-1)(b-1)=2(a−1)(b−1)=2
至此,可以得到a=2,b=3a=2,b=3a=2,b=3或a=3,b=2a=3,b=2a=3,b=2。
但是,我们如何找到形成的序列的最大和呢?
考虑dpdpdp。首先将这个序列按降序排序并去重,用mapmapmap记录下每个数在原序列中出现的次数。
状态设计: dpidp_idpi表示看到第iii个数的最大和。
状态转移:
如果第iii个数是奇数,那么111到i−1i-1i−1的所有数显然不能让它跟在后面,此时dpi=aidp_i=a_idpi=ai;
否则,我们考虑让它跟在第ai2×3\frac {a_i} 2×32ai×3的后面,即dpi=dpx+aidp_i=dp_x+a_idpi=dpx+ai,其中xxx为满足ax=ai2×3a_x=\frac {a_i} 2×3ax=2ai×3的唯一xxx。
我们可以用mapmapmap记录下xxx这个数出现的位置,即可高效进行第二种转移。
时间复杂度O(nlog2n)O(nlog_2n)O(nlog2n),但是由于STLSTLSTL的巨大常数导致在洛谷上跑得比蜗牛还慢(当然过了)。
Code
A
#include <bits/stdc++.h>
#define int long long
using namespace std;
int a,b,c,now,ans;
bool check(int x)
{
int need=(x*(x+1))/2,sumv;
sumv=max(need-a,0ll);
sumv+=max(need-b,0ll);
if (sumv<=c) return true;
else return false;
}
int Binary_search(int l,int r)
{
if (l+1==r||l==r)
{
if (check(r)) ans=max(ans,r);
if (check(l)) ans=max(ans,l);
return ans;
}
int mid=(l+r)>>1;
if (check(mid)) return Binary_search(mid,r);
else return Binary_search(l,mid);
}
signed main()
{
cin>>a>>b>>c;
cout<<Binary_search(0,1e9)<<endl;
return 0;
}
B
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,k,u,v,maxv,cnt,pos;
int a[2000005];
signed main()
{
cin>>n>>k;
for (int i=1;i<=n;i++)
{
cin>>u>>v;
a[u]+=v;
if (u*a[u]>maxv) maxv=u*a[u],pos=u;
}
if (k==0)
{
if (a[pos]>=2) return cout<<maxv<<endl,0;
else return cout<<"NO"<<endl,0;
}
else
{
maxv=0;
for (int i=0;i<=1000000;i++)
{
u=a[i],v=a[i+k];
cnt=min(u,v);
if (cnt>=2) maxv=max(maxv,cnt*i+cnt*(i+k));
}
if (maxv==0) cout<<"NO"<<endl;
else cout<<maxv<<endl;
}
return 0;
}
C
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,pos,ans=0;
int a[300005],b[300005],dp[300005];
map<int,int> m;
map<int,int> m2;
bool cmp(int x,int y)
{
return x>y;
}
signed main()
{
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>a[i];
m[a[i]]++;
}
sort(a+1,a+n+1,cmp);
for (int i=1;i<=n;i++)
{
if (a[i]!=a[i-1]) b[++pos]=a[i];
}
n=pos;
for (int i=1;i<=n;i++)
{
if (b[i]&1) dp[i]=m[b[i]]*b[i],m2[b[i]]+=dp[i];
else dp[i]=m2[(b[i]/2)*3]+b[i]*m[b[i]],m2[b[i]]+=dp[i];
}
for (int i=1;i<=n;i++) ans=max(ans,dp[i]);
cout<<ans<<endl;
return 0;
}
本文深入解析了三道算法竞赛题目,包括高度单调性二分查找、序列最大和求解以及数学问题的DP策略。通过详细阐述解题思路与代码实现,帮助读者掌握高效算法设计与优化技巧。
485

被折叠的 条评论
为什么被折叠?



