口胡(几乎没有代码)

把 AFO 之前口胡的题放这里,一句话题解。

P4113 [HEOI2012]采花

和 HH的项链一样,维护一下第二个出现的值,然后差分,树状数组即可,时间复杂度 \(\mathcal O(n\log n)\)


P2398 GCD SUM

有公式:

\[\sum\limits_{d|n}\varphi(d)=n \]

推式子:

\[\begin{aligned}\sum\limits_{i=1}^n\sum\limits_{j=1}^n\gcd(i,j)&=\sum\limits_{i=1}^n\sum\limits_{j=1}^n\sum_{d|\gcd(i,j)}\varphi(d)\cr&=\sum\limits_{d=1}^n\varphi(d)\left\lfloor\dfrac{n}{d}\right\rfloor^2\end{aligned} \]

整除分块,时间复杂度 \(\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_i=\max\limits_{j=1}^{i-1} \{(dp_j+1)×[|x_{a_i}-x_{a_j}|+|y_{a_i}-y_{a_j}|\leqslant \mathit{\Delta} t]\} \]

然后得到所有 \(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)\) 了。

你可能感兴趣的:(口胡(几乎没有代码))