首页 > 其他分享 >CSP模拟2

CSP模拟2

时间:2024-09-07 16:13:50浏览次数:5  
标签:lceil ch return int frac rceil CSP 模拟

A.不相邻集合

考虑值域上连续的段,可以发现连续的长度为 \(x\) 的段的贡献必定为 \(\lceil{\frac{x}{2}}\rceil\)

考虑并查集维护值域连续的段的大小,每次询问求出全部连续段的 \(\lceil{\frac{size}{2}}\rceil\) 之和即为答案

合并操作:在值域上加入 \(x\),尝试合并 \(x-1\) 与 \(x+1\)

复杂度不对,考虑优化

  1. 记一个关于值域的 \(vis\),若单次插入不改变 \(vis\),则答案不变
  2. 每次在并查集上合并时直接统计答案,先减去两个分别的答案,再加上总和的答案
  3. 记得新加入单点时的贡献为 \(\lceil{\frac{1}{2}}\rceil=1\)
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define void inline void
// #define ONLINE_JUDGE
#ifndef ONLINE_JUDGE
#define test(i) cout<<"test: "<<i<<endl
#define testp(i,j) cout<<i<<" "<<j<<endl
#define testd(i) cout<<i<<" "
#define end cout<<"\n"
#define div <<" "<<
#else
#define test(i)
#define testp(i,j)
#define testd(i)
#define end false
#define div ,
#endif
template<typename T>
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<typename T,typename... Args>
void read(T& x,Args&... args){
    read(x);read(args...);
}
vector<int>has;
int ans=0;
class dsu{
	public:
	int fa[500001],siz[500001];
	void reset(int n){
		for(int i=1;i<=n;++i){
			fa[i]=i;
			siz[i]=1;
		}
	}
	int find(int id){
		if(fa[id]==id) return id;
		fa[id]=find(fa[id]);
		return fa[id];
	}
	void connect(int x,int y){
		int fx=find(x),fy=find(y);
		if(fx!=fy){
			fa[fx]=fy;
			ans-=(siz[fy]+1)/2+(siz[fx]+1)/2;
			siz[fy]+=siz[fx];
			ans+=(siz[fy]+1)/2;
		}
	}
};
dsu d;
int a[300001];
bool vis[500001];
int tot,lastans=0;
int main(){
	int n;
	read(n);d.reset(500000);
	for(int i=1;i<=n;++i){
		read(a[i]);
		if(!vis[a[i]]){
			vis[a[i]]=true;
			has.push_back(a[i]);
			ans++;
			if(vis[a[i]-1]){
				d.connect(a[i],a[i]-1);
			}
			if(vis[a[i]+1]){
				d.connect(a[i],a[i]+1);
			}
		}
		cout<<ans<<' ';
	}
}

B.线段树

设 \(f(n,x)\) 表示对从长度为 \(n\) 的连续段建立线段树(即有 \(n\) 个叶节点),根节点的值为 \(x\),左儿子的值为 \(2x\),右儿子的值为 \(2x+1\) 的情况下的全部节点权值和

可以发现对于根节点儿子的权值,相对于根节点权值的变化只有两种:即乘以一个系数或者加上若干值,也即 \(f(n,x)\) 是关于 \(x\) 的一次函数

设 \(f(n,x)=k_{n}x+b_{n}\),考虑到我们在对此线段树向下分治的时候,总会有 \(\lceil{\frac{n}{2}}\rceil\) 长度的区间被分配到左儿子,\(\lfloor{\frac{n}{2}}\rfloor\) 长度的区间被分配到右儿子,也就是说:

\[f(n,x)=f(\lceil{\frac{n}{2}}\rceil,2x)+f(\lfloor{\frac{n}{2}}\rfloor,2x+1)+x \]

根据上设,可得

\[k_{n}x+b_{n}=k_{\lceil{\frac{n}{2}}\rceil}2x+b_{\lceil{\frac{n}{2}}\rceil}+k_{\lfloor{\frac{n}{2}}\rfloor}(2x+1)+b_{\lfloor{\frac{n}{2}}\rfloor}+x \]

解这个方程,得到

\[\begin{cases}k_{n}=2k_{\lceil{\frac{n}{2}}\rceil}+2k_{\lfloor{\frac{n}{2}}\rfloor}+1\\b_{n}=b_{\lceil{\frac{n}{2}}\rceil}+k_{\lfloor{\frac{n}{2}}\rfloor}+b_{\lfloor{\frac{n}{2}}\rfloor}\end{cases} \]

关于这个递推式的初态,可以感性理解

  • 当 \(n=1\) 时,线段树中只有一个节点 \(x\),因此 \(k_{1}=1,b_{1}=0\)
  • 当 \(n=2\) 时,线段树中只有三个节点 \(x,2x,2x+1\),和为 \(5x+1\),因此 \(k_{1}=5,b_{1}=1\)

其余开 map 记搜即可

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
template<typename T> 
inline T read(){
	T x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=(x<<1)+(x<<3)+(ch-'0');
		ch=getchar();
	}
	return x*f;
}
template<typename T> 
inline T read(T&a){
	T x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=(x<<1)+(x<<3)+(ch-'0');
		ch=getchar();
	}
	return a=x*f;
}
template<typename T>
inline void write(T x){
	if(x<0)x*=-1,putchar('-');
	if(x>9)write(x/10);
	putchar(x%10+'0');
	return;
}
const int p=1e9+7;
map<int,int> K,B;
int k(int n){
	if(n==0) return 0;
	if(n==1) return 1;
	if(n==2) return 5;
	if(K.count(n)) return K[n];
	return K[n]=(2*(k((n+1)/2)+k(n/2))+1)%p;
}
int b(int n){
	if(n==0) return 0;
	if(n==1) return 0;
	if(n==2) return 1;
	if(B.count(n)) return B[n];
	return B[n]=(b((n+1)/2)+b(n/2)+k(n/2))%p;
}
int build(int id,int l,int r,int L,int R){
	if(l>R or r<L) return 0;
	if(L<=l and r<=R){
		return (k(r-l+1)*id%p+b(r-l+1))%p;
	}
    int mid=(l+r)/2;
    return (build((id*2)%p,l,mid,L,R)+build((id*2+1)%p,mid+1,r,L,R))%p;
}
signed main(){
    int T;read(T);
    while(T--){
        int n,l,r;
        read(n);read(l);read(r);
        write(build(1,1,n,l,r)%p);putchar('\n');
    }
}

标签:lceil,ch,return,int,frac,rceil,CSP,模拟
From: https://www.cnblogs.com/HaneDaCafe/p/18401819

相关文章

  • 【程序分享 2】分子动力学模拟 + 数据处理程序
    ​【2】分子动力学模拟+数据处理程序viewSq程序:可视化分子动力学(VMD)模块+ 分析X射线和中子结构因子freud程序:用于原子模拟数据的高通量分析HBCalculator程序:通过VMD可计算分子动力学模拟中氢键密度和强度的一维和二维分布DensityCalculator程序(1D&2D......
  • 【CSP】 202209-2 何以包邮?
    试题编号:202209-2试题名称:何以包邮?时间限制:1.0s内存限制:512.0MB70分DFS解法:#include<bits/stdc++.h>//包含所有标准库#defineN1000//定义常量N为1000#definelllonglong//定义ll为longlong类型的别名usingnamespacestd;llans=0x3f3f......
  • 20240906 模拟赛总结
    期望:100+70+4=174实际:100+70+4=174T1梦熊13连测的原题,刚好前几天订正过。。也就给我狗运到了,,观察性质发现,如果两个点所在直线与坐标轴的夹角越接近\(45^{\circ}\)就越优,转化为找到横坐标差的绝对值和纵坐标差的绝对值的差的最小值的两个点,可以坐标轴旋转,不过可以用更方便......
  • CSP 模拟 28
    T1喜剧的迷人之处在于将\(a\)分解质因数,容易找到满足\(ab\)为平方数的最小\(b\),然后需要让\(b\)乘上一个平方数后在\([L,R]\)中,二分找即可。T2镜中的野兽\[\begin{aligned}&f(x)=\sum\cdots\sum[\gcd=1,\text{lcm}=x]\\&g(x)=\sum\cdots\sum[\gcd\midx,\text{lcm......
  • CF1307(模拟赛记录)
    比赛页面偶然发现一道做过的G;C的罚时:没开longlong,谨记。然后一个小时没想出E……E题面:在一年成功的牛奶生产后,FarmerJohn奖励他的奶牛们它们最喜欢的美味的草。在田里有\(n\)个单位的排成一行的草,每个单位的草有甜味\(s_i\)。FarmerJohn有\(m\)头奶牛,每只都......
  • CSP-2024 第一次
    A分解\(a\)之后可以轻松找到最小的\(b\)满足\((a,b)\)是好的,而其他的\(b\)一定是最小的\(b\)的完全平方数倍。B暴力大战(为啥\(d^3(m)\)甚至\(d^4(m)\)能轻松过1e9啊,赛时以为\(d(m)=\Theta(\sqrtm)\),\(d^3(m)=\Theta(m\sqrtm)\)就没敢写,只写了\(O(m\log......
  • 洛谷 P5658 [CSP-S2019] 括号树
    洛谷P5658[CSP-S2019]括号树题意给定一棵树,每个点有一个括号(或)。定义\(s_i\)表示根节点到\(i\)每个点的括号组成的序列。求每个\(s_i\)中合法括号子串的个数\(f_i\)。思路定义\(g_i\)表示\(s_i\)中以\(i\)结尾的合法括号子串的个数。有\(f_i=f_{fa_......
  • 2024.9.6 模拟赛
    A对于一个子矩阵\((x_1,y_1),(x_2,y_2)\),其元素和为\(\sum_{i=x_1}^{x_2}\sum_{j=y_1}^{y_2}S_i\cdotS_j=(\sum_{i=x_1}^{x_2}S_i)(\sum_{j=y_1}^{y_2}S_j)\),\(O(n^2)\)枚举一下\(S\)的所有子区间的和放进一个桶里再检验一下即可。即对于一个子区间和为\(S_1\),需要累加和......
  • CF1534(模拟赛记录)
    比赛页面ABCD都打的可以,然而E的+10直接葬送了大概率过的F1……先猜了个\(n-k+1\)的结论,但是没有写搜索查正确性(事实上确实不正确),于是两次罚时,第一次是交互格式错了。然后又猜了个\(\min(n-k+1,(n-1)/(k-1))\)的结论,过了几个小的搜索数据(\(n\le6\))的,大一点的没跑,于......
  • 2024.9.6 CF1307 模拟赛记录
    A:各捆干草间互相独立,所以优先移动距\(1\)近的。点击查看代码#include<bits/stdc++.h>#defineintlonglong#definepsbkpush_back#definefstfirst#definescdsecond#defineumapunordered_map#definepqueuepriority_queue#definevcvector#defineendl'\n'......