首页 > 其他分享 >[32](CSP 集训) CSP-S 模拟 3

[32](CSP 集训) CSP-S 模拟 3

时间:2024-09-24 14:47:58浏览次数:1  
标签:frac int 32 集训 return read 节点 now CSP

A 奇观

考虑到 CCF 可以拆开算,答案为 \((ans_c)^2\times ans_f\)

剩下的东西比较少,考虑 DP

我的 dp 是从爆搜改的,设 \(f_{i,j}\) 表示递归到第 \(i\) 层时 \(j\) 的方案数,原始的爆搜代码如下:

int dfs_f2(int now,int id){
    if(now==0) return 1;
    if(now==1) return f_c[0][id];
    if(f_c[now][id]) return f_c[now][id];//cth<<"dfs "<<now<<" "<<id<<endl;
    int res=0;
    if(now!=2){
        for(int i=1;i<=n;++i){
            if(i!=id and hdk.find(i,id)){
                res+=dfs_f2(now-1,i);
                res%=p;
            }
        }
    }
    else{
        for(int i=1;i<=n;++i){
            if(i!=id and hdk.find(i,id)){
                res+=f_c[0][i]*f_c[0][id];
                res%=p;
            }
        }
    }
    return f_c[now][id]=res%p;
}

可以发现该搜索的最大问题在于内层枚举时的循环,注意到此题是完全图删边形成的,因此考虑做容斥,用总方案数减去不合法的,不合法的可以通过枚举得到

我写的 dp 比较异端,看个乐子就行

    scanf("%lld %lld",&n,&m);
    for(int i=1;i<=n;++i){
        f_c[0][i]=n-1;
    }
    for(int i=1;i<=m;++i){
        int x,y;scanf("%lld %lld",&x,&y);
        del_e[x].push_back(y);
        del_e[y].push_back(x);
        f_c[0][x]--;f_c[0][y]--;
    }
    int sum=0;
    for(int i=1;i<=n;++i){
        sum=(sum+f_c[0][i])%p;
    }
    for(int i=1;i<=n;++i){
        f_c[1][i]=fixed(sum-f_c[0][i]);
        for(int j:del_e[i]) f_c[1][i]=fixed(f_c[1][i]-f_c[0][j]);
    }
    sum=0;
    for(int i=1;i<=n;++i){
        sum=(sum+f_c[1][i])%p;
    }
    for(int i=1;i<=n;++i){
        f_c[2][i]=fixed(sum-f_c[1][i]);
        for(int j:del_e[i]) f_c[2][i]=fixed(f_c[2][i]-f_c[1][j]);
    }
    sum=0;
    for(int i=1;i<=n;++i){
        sum=(sum+f_c[2][i])%p;
    }
    int c=sum%p;
    memset(f_c[1],0,sizeof f_c[1]);
    memset(f_c[2],0,sizeof f_c[2]);
    memset(f_c[3],0,sizeof f_c[3]);
    sum=0;
    for(int i=1;i<=n;++i){
        sum=(sum+f_c[0][i])%p;
    }
    for(int i=1;i<=n;++i){
        f_c[1][i]=fixed((sum-f_c[0][i])*f_c[0][i]);
        for(int j:del_e[i]){
            f_c[1][i]=fixed(f_c[1][i]-f_c[0][j]*f_c[0][i]);
        }
    }
    sum=0;
    for(int i=1;i<=n;++i){
        sum=(sum+f_c[1][i])%p;
    }
    for(int i=1;i<=n;++i){
        f_c[2][i]=fixed(sum-f_c[1][i]);
        for(int j:del_e[i]){
            f_c[2][i]=fixed(f_c[2][i]-f_c[1][j]);
        }
    }
    int f=0;
    for(int i=1;i<=n;++i){
        f=(f+f_c[2][i])%p;
    }
    cout<<fixed(c*c%p*f)<<endl;

B 铁路

非常好的题

注意到我们没有必要非得去给每次操作新建边,我们可以直接在树上跳 lca 来用并查集合并,这样能解决我们求节点数目的问题:每进行一次操作,节点数加一,并查集上每进行一次合并,节点数减一

然后考虑怎么优化这个过程,注意到,已经在同一个并查集里的数是不需要合并的,因此我们可以借助并查集维护相关信息来直接跳过这段并查集,那么维护什么东西能快速跳节点呢,因为我们是在向根跳,因此我们直接维护并查集中深度最小的节点编号就好了,维护的时候直接往深度最小的节点跳。有人会问这么跳,万一跳过头了怎么办,其实无所谓,因为既然你能跳过头,说明你的目标节点一定在当前并查集内,直接判断当前点和目标点是否在同一并查集内即可

随后我们需要解决新建节点的问题,因为我们并没有真的新建节点,那么如果它询问我们一个新的节点编号,我们要知道往哪里去找。这是很好办的,因为新建节点的下属节点一定已经被合并在同一个并查集里了,因此我们直接维护一个下标,存储每一个新建节点对应的并查集的深度最小的点就行了

#include<bits/stdc++.h>
using namespace std;
#define io_h
// #include"./include/hdk/lib.h"
namespace reader{
	template<typename T>
	inline void read(T& x){
		x=0;bool sym=0;char c=getchar();
		while(!isdigit(c)){sym^=(c=='-');c=getchar();}
		while(isdigit(c)){x=x*10+c-48;c=getchar();}
		if(sym)x=-x;
	}
	template<size_t N>
	inline void read(char (&str)[N]){
		size_t n=0;char c=getchar();
		while(n<N-1&&!isspace(c)){str[n]=c;c=getchar();++n;}
		str[n]=0;
	}
	template<typename T,typename... Args>
	inline void read(T& x,Args&... args){
		read(x);read(args...);
	}
}
int deep[1000001];
using namespace reader;
template<int size>
struct dsu{
    int fa[size+1],minn[size+1];
    void clear(int n){
        for(int i=1;i<=n;++i){
            fa[i]=i;
            minn[i]=i;
        }
    }
    int find(int id){
        if(id==fa[id]){
            return id;
        }
        fa[id]=find(fa[id]);
        return fa[id];
    }
    void join(int x,int y){
        int fx=find(x),fy=find(y);
        if(fx!=fy){
            fa[fx]=fy;
            if(deep[fx]>deep[fy]){
                minn[fx]=minn[fy];
            }
        }
    }
};
int n,m;
int fa[1000001];
dsu<(int)1e6>d;
int ans=0;
int to[1000001];
void join(int x,int y,int newid){
    // cout<<"join "<<x<<" "<<y<<endl;
    int ori=x;
    while(x!=y){
        // cout<<"... "<<x<<" "<<y<<"("<<deep[x]<<","<<deep[y]<<")"<<endl;
        if(d.find(x)!=x){
            // cout<<"find x("<<x<<")!="<<d.find(x)<<endl;
            x=d.minn[d.find(x)];
            continue;
        }
        if(d.find(y)!=y){
            // cout<<"find y("<<y<<")!="<<d.find(y)<<endl;
            y=d.minn[d.find(y)];
            continue;
        }
        if(deep[x]>deep[y]){
            d.join(x,fa[x]);
            ans--;
            x=fa[x];
        }
        else{
            d.join(y,fa[y]);
            ans--;
            y=fa[y];
        }
    }
    to[newid]=ori;
}
vector<int>e[500001];
void dfs(int now,int last){
    fa[now]=last;
    deep[now]=deep[last]+1;
    for(int i:e[now]){
        if(i!=last){
            dfs(i,now);
        }
    }
}
int main(){
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    read(n,m);
    d.clear(n+m);
    for(int i=1;i<=n-1;++i){
        int x,y;read(x,y);
        e[x].push_back(y);
        e[y].push_back(x);
    }
    dfs(1,0);
    for(int i=1;i<=m;++i){
        int x,y;read(x,y);
        if(x>n) x=to[x];
        if(y>n) y=to[y];
        join(x,y,n+i);
        cout<<n+ans<<endl;
    }
}

C.光纤

非常不好的题

旋转卡壳是好的,就是给你一个凸包,让你维护凸包直径,也就是一条直线到凸包内所有节点的最大距离最小

有一个结论,这样的直线一定与凸包的某一条边平行,所以你只需要绕着凸包转一圈就能搞定这个问题

问题是怎么确定凸包上哪个点到这条直线距离最大,有一个显然的 \(n^{2}\) 做法

但实际上不是的,因为这个决策点也有单调性,所以开一个双指针就做完了

这题不好,唐诗有理数类

一开始用的平面向量求点线距做的,后来调不出来了,所以改叉积了

#include<bits/stdc++.h>
using namespace std;
#define int __int128
#define abs(x) (x>=0?x:-x)
void _print(__int128 x,bool first=true){
	if(x<0){
		putchar('-');
		_print(-x,false);
		return;
	}
	if(x==0){
		if(first) putchar('0');
		return;
	}
	_print(x/10,false);
	putchar((int)(x%10)+'0');
}
namespace reader{
	template<typename T>
	inline void read(T& x){
		x=0;bool sym=0;char c=getchar();
		while(!isdigit(c)){sym^=(c=='-');c=getchar();}
		while(isdigit(c)){x=x*10+c-48;c=getchar();}
		if(sym)x=-x;
	}
	template<size_t N>
	inline void read(char (&str)[N]){
		size_t n=0;char c=getchar();
		while(n<N-1&&!isspace(c)){str[n]=c;c=getchar();++n;}
		str[n]=0;
	}
	template<typename T,typename... Args>
	inline void read(T& x,Args&... args){
		read(x);read(args...);
	}
}
using namespace reader;
class frac{
    private:
        int z,m;
    public:
        frac(int x=0,int y=1){
            z=x,m=y;
            fixed();
        }
        frac fixed(){
            int gcd=__gcd(abs(z),abs(m));
            if(m<0){
                m*=-1;z*=-1;
            }
            if(z==0){
                m=1;return *this;
            }
            if(gcd==0) return *this;
            z/=gcd;m/=gcd;
            return *this;
        }
        frac upside(){
            return frac(m,z);
        }
        frac operator = (pair<int,int>A){
            z=A.first;m=A.second;fixed();
            return *this;
        }
        frac operator + (frac A){
            return (frac(z*A.m+m*A.z,m*A.m)).fixed();
        }
        frac operator * (frac A){
            // cout<<"multi ";this->print();putchar(' ');
            // A.print();putchar('=');
            int gcd1=__gcd(z,A.m);
            int gcd2=__gcd(A.z,m);
            frac ans=(frac((z/gcd1)*(A.z/gcd2),(m/gcd2)*(A.m/gcd1))).fixed();
            // ans.print();putchar('\n');
            return ans;
        }
        frac operator / (frac A){
            return (*this*A.upside()).fixed();
        }
        frac operator -(){
            return frac(-z,m);
        }
        frac operator -(frac A){
            return *this+(-A);
        }
        bool operator <(frac A){
            return z*A.m<A.z*m;
        }
        bool operator ==(frac A){
            return z*A.m==A.z*m;
        }
        bool operator >(frac A){
            return !(*this==A and *this<A);
        }
        void print(){
            fixed();
            _print(z);putchar('/');_print(m);
            // cout<<z<<"/"<<m<<endl;
        }
        frac _abs(){
            return frac(abs(z),abs(m));
        }
        long double it(){
            return z*1.0/m;
        }
};
int n;
int q[1000001],top;
int q1[1000001],top1;
struct node{
	__int128 x,y;
}d[1000001],sta[1000001];
#define K(i,j) ((double)(d[j].y-d[i].y)/(d[j].x-d[i].x))
int cha(int x,int y,int z){
    return (d[y].x-d[x].x)*(d[z].y-d[x].y)-(d[y].y-d[x].y)*(d[z].x-d[x].x);
}
int len(int x,int y){
    return (d[y].x-d[x].x)*(d[y].x-d[x].x)+(d[y].y-d[x].y)*(d[y].y-d[x].y);
}
frac ans;
char anss[1000001];
inline void print(__int128 x){
	if(!x)putchar('0');
	else{
		if(x<0)x=-x,putchar('-');
		int cnt=0;
		while(x)anss[++cnt]=x%10+'0',x/=10;
		for(int i=cnt;i;--i)
			putchar(anss[i]);
	}
}
signed main(){
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
	read(n);
	if(n<=2){
        ans.print();
        return 0;
    }
	for(int i=1;i<=n;++i){
		read(d[i].x,d[i].y);
    }
	sort(d+1,d+1+n,[](const node&x,const node&y){return x.x==y.x?x.y<y.y:x.x<y.x;});
	n=unique(d+1,d+1+n,[](const node&x,const node&y){return x.x==y.x&&x.y==y.y;})-d-1;
	for(int i=1;i<=n;++i){
		while(top>1 and (K(q[top],i)<=K(q[top-1],q[top]))){
			--top;
		}
		q[++top]=i;
	}
	for(int i=n;i;--i){
		while(top1>1 and K(i,q1[top1])<=K(q1[top1],q1[top1-1]))--top1;
		q1[++top1]=i;
	}
	for(int i=2;i<top1;++i){
		q[++top]=q1[i];
	}
	for(int i=1;i<=top;++i){
		sta[i]=d[q[i]];
    }
	for(int i=1;i<=top;++i){
		d[i]=sta[i];
    }
    int now=1;
	for(int i=1;i<=top;++i){
		while((now==(i==top?1:i+1))||((abs(cha(now,i,(i==top?1:i+1))))<=(abs(cha((now==top?1:now+1),i,(i==top?1:i+1)))))){
			now=(now==top?1:now+1);
		}
		if(ans==frac(0,1) or ans.it()>(double)cha(now,i,(i==top?1:i+1))*cha(now,i,(i==top?1:i+1))/len(i,(i==top?1:i+1))){
            ans=frac(cha(now,i,(i==top?1:i+1))*cha(now,i,(i==top?1:i+1)),len(i,(i==top?1:i+1)));
        }
	}
    (ans*frac(1,4)).print();
}

标签:frac,int,32,集训,return,read,节点,now,CSP
From: https://www.cnblogs.com/HaneDaCafe/p/18429082

相关文章

  • OpenMV与STM32通信
    引言在现代嵌入式系统开发中,计算机视觉及图像处理的需求日益增加。OpenMV是一款适合初学者和开发者的图像处理模块,能够简化视觉任务的开发。与之相对,STM32是一个广泛应用的微控制器系列,因其强大的性能和灵活性而备受青睐。通过将OpenMV与STM32进行通信,开发者可以将视觉处理功......
  • FormatConvertedBitmap DestinationFormat Gray32Float BlackWhite
     <Windowx:Class="WpfApp410.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.micros......
  • ESP32 本地大模型部署语音助手
    ESP32S3Box提供了chatgpt的demo。因为访问不了的原因,打算改来做一个本地化部署的专用语音助手。文章目录准备工作Windows安装ESP-IDFWSL安装ESP-IDF配置IDF编译chatgptdemo串口映射下载语音助手调试步骤遇到的问题在WSL2中,server.py脚本无法被ESP访问端......
  • 【刷题笔记】2020 CSP-J
    2020CSP-J题目整理B-直播获奖思路梳理题目中说“如有选手成绩相同,则所有成绩并列的选手都能获奖,因此实际获奖人数可能比计划中多”,这是一个坑点,因为即使有分数相同的人,他的分数也是和位于第\(n*w\%\)人的分数相同的,而题目只让输出分数,所以不用在意。先来考虑暴力算法,没加进......
  • 【刷题笔记】2019 CSP-S
    2019CSP-S题目整理A-格雷数思路简介思路很简单,如果编号在中点的左边那么就输出0,否则输出1,同时还要改变编号。代码实现#include<bits/stdc++.h>#definemaxn80usingnamespacestd;typedef__int128int1;int1n,k;__int128read(){ charch=getchar(); __int128......
  • 14.STM32F103C8T6+CUBEMX+循迹模块(定时器计数、测速)
        学习完b站keysking老师的视频后写了这篇笔记,主要是学习定时器外部时钟。    用的是TIM2(有ETR,TIM3和TIM4都没有)一、cubemx配置(没加无上限计数)1、开TIM2    选了外部时钟模式1,借助从模式ETR1;        下面改数值15是输入滤波器,因为抖动......
  • 2024csps初赛记
    对于此次初赛,教训有不少,有一些差点把自己整死。第一点,铅笔只能用2B,不要尝试使用HB2nd:一定要带涂卡笔和橡皮,不然就算借别人用了也会发现橡皮还不如手擦的干净(可能因为这个原因我都要丢几分)。3rd:这是新的不属于失误的经验,尽管做了多套历年题目,但考试的题目难度可不能用不完全归纳......
  • NOIP2024集训Day36 DP优化
    NOIP2024集训Day36DP优化A.[NOIP2023]天天爱打卡前段时间才看过这道题。dp+线段树优化+离散化。经典。考虑朴素dp。定义\(f_i\)表示考虑到第\(i\)个位置,并钦定第\(i\)天跑步的最大能量值。枚举最后一段跑步时间,有:\(f_i=\max(\max\limits_{k\ltj}f_k-(i-......
  • 9.23 csp
    今天模拟赛出了四道zroi的题,挺GG的。T1、奇观因为删除的边比较少,所以从m入手,f[i][j]表示长度为i,终点为j的链的方案数。C是长度为3的链,F是1条长度为3的链和2条长度为2的链。输出CCF即可GT2、铁路救命的签到题。因为每次合并时每走一个点就会减少一个点,所以我们......
  • [赛记] csp-s模拟3
    奇观55pts赛时打的$\Theta(n^5)$和$m=0$的特殊性质拿了55pts;考虑正解,首先,$CCF$这三个字母是可以分开维护的;对于$C$,其可以看作一个连了四个点的线段,对于$F$,其可以看作一个连了三个点的线段在再最后分别多连两个点;设$f_{i,j}$表示维护一个连了$i$......