标签:剖分 int ans 样例 long 树链 第四天 杭州 集训
今天是本蒟蒻在杭州集训(被虐)的第四天,由于我太弱了,出题人不屑于浪费时间出毒瘤题来坑我;而是从洛谷上
挪了些原题上来;但由于我太弱了,还是没做出来;
T1 . 坐等 memset0
树链剖分是个喜欢逛讨论区的女孩子。
树链剖分看到有若干个小学生发的帖子,因为一些原因,这些帖子形
成了一条链。
其中第 i(1<=i< n)个帖子和第 i+1 个帖子用双向边相连
树链剖分举报了这些帖子,然后作为管理员的 memset0,决定对帖子
进行删除。
其中第 i 个帖子有一个小学生值 a.
但是, 因为 memset0 太强了, memset0 不屑于对小学生值在[l,r] 区
间内的帖子进行删除,只和谐掉其他帖子。(即,只保留小学生值[l,r
的帖子)
现在,树链剖分想到一个问题,就是在这个保留下来的帖子里,联通
块的个数是多少。
问题还没完
我们把只保留小学生值[l,r]的帖子使得这些帖子的联通块的个数记
为
求
输入:
第一行一个正整数 n
第二行 n 个正整数 a[i]
输出
一行一个正整数,表示答案
样例输入
4
2 1 1 3
样例输出
11
对于 40%的数据 n <= 100
对于 60%数据 n <= 1000
对于 100%数据 n <= 100000,1<=a[i]<=n 且为正整数
这题在洛谷原题是CF1151E有兴趣的可以去做一下;
然后,我讲下这题怎么做,首先如果打暴力的话是只有60分;
接下来,我讲讲从隔壁大佬那学来的正解:
考虑每个点对答案的贡献,我们认为一个连通块里让编号最大的点
产生贡献,对于点 i,要产生贡献就一定要这个点存在,而点 i+1不
存在而点n只用包含这个点就行了
具体是这样的:
当 a i>a i+1 贡献=(a i-a i+1)*(n-a i+1)
当 a i<a i+1 贡献=(a i+1-a i)*a i;
具体代码如下:
#include<bits/stdc++.h> using namespace std; long long n; long long ans; long long a[1000005]; int main() { scanf("%lld",&n); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); } for(int i=1;i<n;i++) { int x=a[i],y=a[i+1]; if(x>y) { ans=(long long)ans+(x-y)*(n-x+1); } else { ans=ans+(long long)(y-x)*x; } } ans+=(long long)a[n]*(n-a[n]+1); cout<<ans; return 0; }
T2.吊打集训队: 树链剖分是一个喜欢膜巨佬的女孩子 一天树链剖分正在看 WXW 吊打集训队。 WXW 在数轴的 0 位置,其中数轴上的整点(包括 0)上有一个队爷。 如果当前 wxw 在位置 k,则 wxw 可以跳到 k+a 或 k-b 位置。wxw 只要 在一个位置上,就可以吊打该位置的集训但是 WXW 觉得这样很无聊, 于是他搞了一个函数 f(X)表示 wxw 只能 在区间[0,x]中吊打集训队(wxw 只能在区间[0,x]里面,无法出来),从 开始最多能吊打的队爷。 注:wxw 可以多次经过同一个位置,但同一个位置只算吊打一个队爷 wxw 想要求∑ m i=0 f(i) 输入: 3 个正整数 m,a,b 输出 Wxw 想要求的结果 样例输入 7 5 3 样例输出 19 样例输入 2 6 4 5 样例输出 2 10 数据范围: 对于 20%的数据 m,a,b <= 100 对于 40%数据 m,a,b <= 1000 对于 60%的数据 m,a,b <= 100000 对于 100%的数据 m <= 1000,000,000 a,b <= 100,00
这题也是洛谷原题,题号是:CF1146D;
这题写暴力的话只有40分;
下面我来说一下正解:
先暴力求出前2*max(a,b)的方案数
在通过打表找到规律:
当 i>2*max(a,b)时;
f(i)=i/gcd(a,b)+1;
(其实i > a+b就有规律了)
关于这个规律的证明
首先用exgcd可以说明 不是gcd(a,b)倍数的点无法到达
ax-by = gcd(a,b)*k
现在可以用exgcd求出x,y
然后我们就是要走x个a,y个b
假如a < b的话
那么就wxw就可以走若干个+a,直到大于b时候往回跳一次,然后继续+a
a>b同理
代码如下:
#include<bits/stdc++.h> using namespace std; long long n; long long ans; long long a,b,i; long long gcd(long long a,long long b){return b?gcd(b,a%b):a;} int main() { scanf("%lld%lld%lld",&n,&a,&b); ans+=a; int d=gcd(a,b); if(n<a){ printf("%d",n+1); return 0; } long long tot=1,w=0; for(i=a;i<=2*max(a,b);i++) { while(w+a<=i) { tot+=(i-w)/a; w+=(i-w)/a*a; tot+=w/b; w-=w/b*b; if(!w) break; }if(!w) break; ans+=tot; if(i==n) break; } if(!w) { long long d=gcd(a,b); long long g=i/d+1; long long k=n/d+1; long long sum=(long long)(n/d)*d; ans+=(long long)(g+k)*(sum-i+d)/2; long long total=0; for(long long j=n+1;j<sum+d;j++) { total+=(long long)j/d+1; } ans-=total; } cout<<ans; return 0; }
T3:Ynoi: 树链剖分是个爱出题的女孩子。 ccz 出了一道数据结构题,结果太毒瘤了,树链剖分不会做 czz 也出了一道数据结构题,结果还是太毒瘤了, 树链剖分还是不会 做 树链剖分也出了一道数据结构题,结果太水了,被大家秒了 后来,ccz,czz,树链剖分决定合出一道题 然后 ccz 觉得树链剖分太菜了,不屑于一起参与出题,于是去找 lxl 一 起出 Ynoi 了。 czz 也觉得树链剖分太菜了,但还是随手说了两个询问操作。 树链剖分:“那我干啥呢?” czz:“你这么菜,出出来的题也是被大家秒掉。” 树链剖分:“好吧,那我造数据吧。 ” 结果由于树链剖分太菜了,她造的数据全是随机的。 现在有一个 1~n 的排列 a, 现在有以下操作 1 l r p 求 a[i]模 p 后的值在模 p 意义下的逆元的最大值(l <= i <= r)(保 证 p 为质数,p <= 100000)(如果 a[i]是 p 的倍数,则认为逆元是 0) 2 l r k 对于序列的第 i 个数,表示 i 号点,从 a[i]向 i 连一条有向边, 求从点 i(l<=i<=r)开始出发恰好经过 k 条边,到的点编号的最大值(可以 多次经过同一个点)。如果没有这样的点,输出-1; 保证数据随机 输入: 第一行 两个正整数 n,m 表示序列长度和询问次数 第 2~m+1 行,每行若干个整数,表示一个操作 输出: m 行,输出一个数,询问的答案
样例输入 5 2
4 3 1 5 2
1 1 4 3
2 2 5 3
样例输出
2
4
数据范围 20%数据 n,m <= 100 50%数据 n,m <= 1000 100%数据 n,m <= 100000 , 所有输入的数均为正整数且小于等于 n。 1 <= l <= r <= n,且随机生成。 这题是出题人随手出的一道题,然后我就连暴力都打不来了; 经过隔壁大佬的一下午教导;我终于学会了正解; 其实也蛮简单的;第一个询问,从p-1到0枚举答案,求逆,判断是否在区间[l,r]内,如果在就输出并退出
第二个询问一样,从n~1枚举答案,倍增(或用成环,因为是个排列)判断k步前是哪个点。
代码如下:
#include<bits/stdc++.h> using namespace std; int n,m; struct adw{ int ma,zhi; }a[110005]; int b,l,r,p,k,z; int f[110000]; int fa[110000][21]; int w[21]; int q[110000]; int rd(){ int s=0,ff=1; char ww=getchar(); while(ww<'0'||ww>'9'){ if(ww=='-') ff=-1; ww=getchar(); } while(ww>='0'&&ww<='9'){ s=s*10+(ww-'0'); ww=getchar(); } return s*ff; } int kuai(int a,int b,int p) { int sum=1; while(b) { if(b&1) sum=(long long)sum*a%p; a=(long long)a*a%p; b=(b>>1); } return sum; } void work() { bool h=0; for(int i=p-1;i>=0;i--) { int c=kuai(i,p-2,p); for(int j=c;j<=n;j+=p) { if(a[j].ma>=l&&a[j].ma<=r) { printf("%d\n",i); h=1; break; } } if(h==1) break; } } void dfs(int x,int d) { if(f[x]){q[x]=d; return;} f[x]=1; dfs(a[x].zhi,d+1); q[x]=q[a[x].zhi]; } int QWQ(int x,int s) { for(int i=z;i>=0;i--) { if(s>=w[i]) { s-=w[i]; x=fa[x][i]; } } return x; } void QwQ() { for(int i=n;i>=1;i--) { int ch=QWQ(i,k%q[i]); if(ch>=l&&ch<=r) { printf("%d\n",i); break; } } } int main() { n=rd(); m=rd(); w[0]=1; z=log2(n); for(int i=1;i<=n;i++) { a[i].zhi=rd(); a[a[i].zhi].ma=i; fa[i][0]=a[i].zhi; } for(int i=1;i<=z;i++) w[i]=(w[i-1]<<1); for(int i=1;i<=n;i++) if(f[i]==0) dfs(i,0); for(int i=1;i<=z;i++) for(int j=1;j<=n;j++) fa[j][i]=fa[fa[j][i-1]][i-1]; for(int i=1;i<=m;i++) { b=rd(); if(b==1) { l=rd(); r=rd(); p=rd(); work(); } if(b==2) { l=rd(); r=rd(); k=rd(); QwQ(); } } return 0; }
以上就是我被虐的全部过程;
来自一个蒟蒻;
标签:剖分,int,ans,样例,long,树链,第四天,杭州,集训 来源: https://www.cnblogs.com/hong13/p/11166431.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。