2022.9.26测试

一测:300pts,打树剖一定要单独写操作函数。

今天挺水的,不细讲

T1:P1661 扩散(黄)

T2:P2590 [ZJOI2008]树的统计(蓝)(0pts

T3:1644:【例 4】佳佳的 Fibonacci(估计在绿左右吧)

T4:P1627 [CQOI2009] 中位数(绿)


T1:

通过模拟可知,每过 k 秒,这个点可以覆盖到曼哈顿距离小于 k 的所有点。

可以预处理出来两个点之间的曼哈顿距离 dis,那么这两个点会成为连通块的时间为 dis÷2,(x,表示对 x 向上取整)。

由于 N50,所以剩下的只要用到并查集,随便乱搞都可以。

这里选择最小生成树,对每两个点建边,边权为 dis÷2。然后答案为生成树中最大的边。

时间复杂度:O(n2×log(n2))

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=55;
int n,x[N],y[N],cnt,f[N];
struct node
{
	int from,to,data;
}a[N*N];
inline int tabs(int x)
{
	return x>0?x:-x;
}
int cmp(node fi,node se)
{
	return fi.data<se.data;
}
int afind(int x)
{
	if(f[x]==x)return x;
	return f[x]=afind(f[x]);
}
int krus()
{
	int res=0,num=n;
	for(int i=1;i<=cnt;i++)
	{
		if(afind(a[i].from)==afind(a[i].to))continue;
		f[afind(a[i].from)]=afind(a[i].to);
		num--;
		res=a[i].data;
		if(num==1)break;
	}
	return res;
}
int main()
{
	freopen("big.in","r",stdin);
	freopen("big.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d%d",&x[i],&y[i]),f[i]=i;
	for(int i=1;i<=n;i++)
	{
		for(int j=i+1;j<=n;j++)
		{
			a[++cnt].from=i;
			a[cnt].to=j;
			a[cnt].data=(tabs(x[i]-x[j])+tabs(y[i]-y[j])+1)/2;
		}
	}
	sort(a+1,a+1+cnt,cmp);
	int ans=krus();
	printf("%d",ans);
	return 0;
}

T2:

树剖模板,注意修改点时是修改其在线段树的下标的点,样例太水没检查出来。

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int N=3e4+5;
int n,dep[N],son[N],fa[N],topp[N],id[N],t[N],w[N],f[4*N],m[4*N],cnt,nl,nr,k;
vector<int>a[N];
int dfs1(int x,int fath)
{
    fa[x]=fath;
    dep[x]=dep[fath]+1;
    int maxn=-1,sum=1;
    int len=a[x].size();
    for(int i=0;i<len;i++)
    {
        if(a[x][i]==fath)continue;
        int num=dfs1(a[x][i],x);
        if(num>maxn)maxn=num,son[x]=a[x][i];
        sum+=num;
    }
    return sum;
}
void dfs2(int x,int tp)
{
    id[x]=++cnt;
    w[cnt]=t[x];
    topp[x]=tp;
    int len=a[x].size();
    if(son[x])dfs2(son[x],tp);
    for(int i=0;i<len;i++)
    {
        if(a[x][i]==fa[x]||a[x][i]==son[x])continue;
        dfs2(a[x][i],a[x][i]);
    }
}
inline int ls(int x)
{
    return x<<1;
}
inline int rs(int x)
{
    return x<<1|1;
}
inline void pushup(int x)
{
    f[x]=f[ls(x)]+f[rs(x)];
    m[x]=max(m[ls(x)],m[rs(x)]);
}
void build(int x,int l,int r)
{
    if(l==r)
    {
        f[x]=m[x]=w[l];
        return;
    }
    int mid=(l+r)>>1;
    build(ls(x),l,mid);
    build(rs(x),mid+1,r);
    pushup(x);
}
void update(int x,int l,int r)
{
    if(l==r)
    {
        f[x]=m[x]=k;
        return;
    }
    int mid=(l+r)>>1;
    if(mid>=nl)update(ls(x),l,mid);
    else update(rs(x),mid+1,r);
    pushup(x);
}
int search1(int x,int l,int r)
{
    if(l>=nl&&r<=nr)return f[x];
    int mid=(l+r)>>1,sum=0;
    if(mid>=nl)sum+=search1(ls(x),l,mid);
    if(mid<nr)sum+=search1(rs(x),mid+1,r);
    return sum;
}
int search2(int x,int l,int r)
{
    if(l>=nl&&r<=nr)return m[x];
    int mid=(l+r)>>1,maxn=-1e9;
    if(mid>=nl)maxn=max(maxn,search2(ls(x),l,mid));
    if(mid<nr)maxn=max(maxn,search2(rs(x),mid+1,r));
    return maxn;
}
int search1_road(int x,int y)
{
    int sum=0;
    while(topp[x]!=topp[y])
    {
        if(dep[topp[x]]<dep[topp[y]])swap(x,y);
        nl=id[topp[x]],nr=id[x];
        sum+=search1(1,1,n);
        x=fa[topp[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    nl=id[x],nr=id[y];
    sum+=search1(1,1,n);
    return sum;
}
int search2_road(int x,int y)
{
    int maxn=-1e9;
    while(topp[x]!=topp[y])
    {
        if(dep[topp[x]]<dep[topp[y]])swap(x,y);
        nl=id[topp[x]],nr=id[x];
        maxn=max(maxn,search2(1,1,n));
        x=fa[topp[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    nl=id[x],nr=id[y];
    maxn=max(maxn,search2(1,1,n));
    return maxn;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        a[u].push_back(v);
        a[v].push_back(u);
    }
    for(int i=1;i<=n;i++)scanf("%d",&t[i]);
    dfs1(1,0);
    dfs2(1,1);
    build(1,1,n);
    int q;
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        char opt[10];
        scanf("%s",opt+1);
        if(opt[2]=='M')
        {
            int x,y;
            scanf("%d%d",&x,&y);
            int ans=search2_road(x,y);
            printf("%d\n",ans); 
        }
        if(opt[2]=='S')
        {
            int x,y;
            scanf("%d%d",&x,&y);
            int ans=search1_road(x,y);
            printf("%d\n",ans);
        }
        if(opt[2]=='H')
        {
            scanf("%d%d",&nl,&k);
            nl=id[nl];
            update(1,1,n);
        }
    }
    return 0;
}

T3:

貌似有二维斐波那契的做法,但这里讲矩阵加速。

可以很快的构造出一个初始矩阵 m1

[sumi×fii×fi1fifi1]

然后转移矩阵就很好建了 m2

[1111101111010100001100010]

不太懂的可以自己乘一下即可。

然后求 m2n2×m1

答案即为 sum+1×f1+2×f2

复杂度为 O(25×log(n))

#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
int n,mod;
struct matrix
{
	int x,y,a[6][6];
	void init()
	{
		for(int i=1;i<=5;i++)for(int j=1;j<=5;j++)a[i][j]=0;
	}
};
matrix operator *(matrix fi,matrix se)
{
	matrix th;
	th.init();
	th.x=fi.x,th.y=se.y;
	for(int i=1;i<=fi.x;i++)
	{
		for(int j=1;j<=se.y;j++)
		{
			for(int k=1;k<=fi.y;k++)
			{
				th.a[i][j]+=fi.a[i][k]*se.a[k][j];
				th.a[i][j]%=mod;
			}
		}
	}
	return th;
}
matrix quick_pow(matrix x,int y)
{
	matrix num=x,sum;
	sum.init();
	sum.x=sum.y=5;
	for(int i=1;i<=5;i++)sum.a[i][i]=1;
	while(y)
	{
		if(y&1)sum=sum*num;
		num=num*num;
		y>>=1;
	}
	return sum;
}
signed main()
{
	freopen("jiajia.in","r",stdin);
	freopen("jiajia.out","w",stdout);
	scanf("%lld%lld",&n,&mod);
	if(n==1)
	{
		printf("1");
		return 0;
	}
	matrix a,b;
	a.init();
	a.x=a.y=5,a.a[1][1]=a.a[1][2]=a.a[1][3]=a.a[1][4]=a.a[1][5]=a.a[2][2]=a.a[2][3]=a.a[2][4]=a.a[2][5]=1;
	a.a[3][2]=a.a[3][4]=a.a[4][4]=a.a[4][5]=a.a[5][4]=1;
	b.x=5,b.y=1;
	b.a[1][1]=3,b.a[2][1]=2,b.a[3][1]=2,b.a[4][1]=1,b.a[5][1]=1;
	a=quick_pow(a,n-2);
	b=a*b;
	printf("%lld",b.a[1][1]);
	return 0;
}

T4:

思维题。

对于数 k,当一个序列中比数 k 大的数等于比 k 小的数,那么 k 就是这个序列的中位数。

那么就预处理出来一个连续序列中比 k 大的数个数与比 k 小的数个数的差。

从数 k 的下标开始,往前遍历,遇到比自己大的计数器 +1,否则 1。然后往再后遍历也是如此。

用桶记录往前遍历与往后遍历的结果,枚举一对相反数,将两边方案数相乘即可。

负数下标可以让所有的下标加上 105

复杂度:O(n)

#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
const int N=1e5+5;
int n,k,a[N],vis1[2*N],vis2[2*N],beg;
signed main()
{
	freopen("mid.in","r",stdin);
	freopen("mid.out","w",stdout);
	scanf("%lld%lld",&n,&k);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		if(a[i]==k)beg=i;
	}
	int num=0,m=N-5;
	for(int i=beg;i>0;i--)
	{
		if(a[i]>k)num++;
		if(a[i]<k)num--;
		vis1[num+m]++;
	}
	num=0;
	for(int i=beg;i<=n;i++)
	{
		if(a[i]>k)num++;
		if(a[i]<k)num--;
		vis2[num+m]++;
	}
	int ans=vis1[m]*vis2[m];
	for(int i=0;i<m;i++)ans+=vis1[i]*vis2[2*m-i]+vis2[i]*vis1[2*m-i];
	printf("%lld",ans);
	return 0;
}
posted @   Gmt丶Fu9ture  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示