把 AFO 之前口胡的题放这里,一句话题解。
P4113 [HEOI2012]采花
和 HH的项链一样,维护一下第二个出现的值,然后差分,树状数组即可,时间复杂度 \(\mathcal O(n\log n)\)。
P2398 GCD SUM
有公式:
推式子:
整除分块,时间复杂度 \(\mathcal O(n+\sqrt{n})\)。
P1314 聪明的质监员
发现 \(y_i\) 是单调的,求完和还是单调的。
那么二分一个 \(W\),对于序列每次维护一个前缀和,对每个区间差分一下,就能 \(\mathcal O(1)\) 了,时间复杂度 \(\mathcal O((n+m)\log w_i)\)。
P6625 [省选联考 2020 B 卷] 卡牌游戏
省选的橙题也是挺有意思的.jpg
首先,题解中的做法我并没有想到。
但着不代表这题不可做,,,
我们考虑什么时候收手合并,当然是负数了!
如果负数后面有个很大的数呢?
如果费力把后面的数纳入现在的卡,那么就会少一次合并机会,得不偿失,所以只要是非负数就合并为一个卡,同时更新 \(sum\)。
记录一下合并完的卡片,作为第一张,第二张用一个动态的指针来记录一下,记得判断是否已经到了最后一张卡片,如果是的话并且总和比 \(0\) 大,就加上,还有就是要注意 long long
。
时间复杂度是 \(\mathcal O(n)\)。
\(Code\):
#include"iostream"
#include"cstdio"
#include"cmath"
#include"cstring"
using namespace std;
#define read(x) scanf("%d",&x)
#define MAXN 100005
#define ll long long
int n,a[MAXN];
ll sum=0,fir=0;
ll now=0;
int lst=2;
int main()
{
read(n);for(int i=1;i<=n;i++) read(a[i]);
fir=a[1];
while(lst<=n)
{
now=fir+(ll)a[lst];
if(lst==n&&now>=0) sum+=now;
lst++;
int k=lst;
for(int i=k;i<=n;i++)
{
if(now>=0){sum+=now,fir=now;break;}
now+=a[i],lst++;
if(i==n&&now>=0) sum+=now;
}
}
printf("%lld\n",sum);
return 0;
}
P2285 [HNOI2004]打鼹鼠
真就 \(\mathcal O(m^2)\) 啊?
\(dp\) 似乎很显然,并没有蓝题难度。
记 \(dp_i\) 为最后敲的鼹鼠为第 \(i\) 只鼹鼠时最多的得分,那么:
然后得到所有 \(dp\) 数组中的最大值即可,注意 \(dp_1=1\) ,假设第一个一定能用。
#include"iostream"
#include"cstdio"
#include"cmath"
#include"cstring"
using namespace std;
#define MAXN 10005
int n,m;
struct node
{
int t,x,y;
}a[MAXN];
int dp[MAXN]={0},ans=1;
inline int read()
{
int x=0;
char c=getchar();
while(c>'9'||c<'0'){c=getchar();}
while(c<='9'&&c>='0'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x;
}
inline int dis(int l,int r){return abs(a[l].x-a[r].x)+abs(a[l].y-a[r].y);}
int main()
{
n=read(),m=read();
for(register int i=1;i<=m;++i) a[i].t=read(),a[i].x=read(),a[i].y=read();
dp[1]=1;
for(register int i=2;i<=m;++i)
{
for(register int j=m-1;j>=1;--j)
{
if(a[i].t-a[j].t>=dis(i,j)) dp[i]=max(dp[i],dp[j]+1),ans=max(ans,dp[i]);
}
}
printf("%d\n",ans);
return 0;
}
\(C++ 14+O_2\) 就真快啊
UVA11572 唯一的雪花 Unique Snowflakes
紫书上给出了 \(\mathcal O(n\log n)\) 的做法,所以我给出了写法比较麻烦一些的 \(\mathcal O(n)\) 做法。
考虑对每个点维护下一个出现此颜色的位置,并在每个位置记录有是否有前面的点把他标记了。
最后维护一个指针标记一下,如果这个点和他下一个都在一个暂时的最小区间中,就更新最小区间,并不断处理扫过区间的弹出。
这样就能 \(\mathcal O(n)\) 了。