7.19 讲题
作者:互联网
消防局的设立;luogu2279
定根之后,找到这棵树中深度最深的叶子节点:
1.自己 2.兄弟 3.父亲 4.爷爷
应该选择哪一种?
显然是4,因为把士兵放在1 2 3位置能覆盖的所有节点,放在4都可以被覆盖;
找出深度最深的节点,找到他的爷爷,在爷爷的位置放一个士兵,把它爷爷能覆盖到的所有节点直接从树中删掉;
重复直到没有节点;
BZOJ 2313
实际上算的是M分组方案
step1:求出有多少种分组方案
求因子个数 for i=1~√n =>有k个因子
step2:求有多少种颜色数
计算M^k =>quick_pow
up:
不考虑人在分组中的顺序,但要考虑不同人分配在同一组产生的差异:(有点乱,举个例子:假设6个人,编号为1 2 3 4 5 6,那么分组的话:(123)(456)与(124)(356)是不同的,而(312)(564)与(123)(456)是相同的)
只要组内的人不完全相同,就认为是不同的两种方案;
第一组的方案数:从n个人选n/r个人出来Cnn/r
第二组的方案数:从剩下的n-n/r个人中选出n/r个人Cn-n/rn/r
……
第n组的方案数:从剩下n/r个人中选出n/r个人
最后因为不考虑排列方式,因此我们还要再除r!
problem 1:论如何求上面的公式
problem 2:k(也就是上述式子)应该去mod多少;
solve problem 1:、
化简上述式子:
solve problem 2:
运用欧拉定理:
因此k%φ(1e9-401);
problem 3: n这么大,阶乘该怎么算
solve:1e9-401是一个质数,
那么φ(1e9-401)=1e9-402=2*13*5281*7283;
转化为n!%2,n!%13,n!%5281,n!%7283;
然后用中国剩余定理??合并方程;
模的数非常小,意味着一定有循环节
开始懵逼?????
求N!%13:
先要知道什么样的(x,y)是先手必胜的:
①把黑色格子到顶端的距离缩小
②把黑色格子到左端的距离缩小
③把黑色格子到低端的距离缩小
④把黑色格子到右端的距离缩小
可以看做有四堆石子的nim石子游戏,
四堆石子分别是:
①x-1个石子
②y-1个石子
③n-x个石子
④m-y个石子
显然先手必胜或必败,只需要异或一下:
对于1<=x<=n,1<=y<=m。
使得(x-1)^(y-1)^(n-x)^(m-y)=0;
优化枚举过程:
问有多少个x,y,满足(x-1)^(n-x)=(y-1)^(m-y)(异或相同为0不同为1,若两边相等,异或以后为0)
首先枚举x,求出所有可能值,放到一个数组里,然后每计算一个y,看在数组中出现了几次。排序+二分的思想(或者使用桶排思想),然后就好了。
CF 45GPrime Problem
代码最长的是判断一个数是不是质数;
哥德巴赫猜想:
任何一个大于等于4的偶数,可以被拆成两个质数之和;未证明
任何一个大于等于7的奇数,可以被拆成三个质数之和;已证明
S=n*(n+1)/2
if (S%2==0) printf("2");
if(S%2==1) S是一个质数当且仅当n=2;
当n=2时 输出1;
如果S-2是质数 输出2
否则 输出3
啊啊啊啊啊啊啊啊啊啊啊啊太艰难了
以下是CODE:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define ll long long using namespace std; ll n,sum; ll ans[10010]; bool notp[18003001]; void prime(ll sum){ notp[1]=1;notp[0]=1; for(ll i=2;i<=sum;i++){ if(notp[i]) continue; for(ll j=i*i;j<=sum;j+=i) notp[j]=1; } } void print(){ for(ll i=1;i<=n;i++) cout<<ans[i]<<" "; return; } int main(){ cin>>n; for(ll i=1;i<=n;i++) ans[i]=1; sum=n*(n+1)/2; prime(sum); if(!notp[sum]) { print(); return 0; } ll u=-1; for(ll i=2;i<sum-1;i++) if((!notp[i])&&(!notp[sum-i])) u=i; if(u==-1){ ans[3]=3;sum-=3; for(ll i=2;i<sum-1;i++) if((!notp[i])&&(!notp[sum-i])) u=i; } for(ll i=n;i>=1;i--){ if(i<=u&&ans[i]==1){ u-=i; ans[i]=2; } } print(); return 0; }View Code
显然对于任意两头牛的曼哈顿距离都是|x1-x2|+|y1-y2|
我们不妨假设x1>=x2;
那么就变成了x1-x2+|y1-y2|;
两种情况:
①:y1>y2:x1-x2+y1-y2=(x1+y1)-(x2+y2)
②:y1<y2:x1-x2+y2-y1=(x1-y1)-(x2-y2);
按照x+y排一遍序,按照x-y排一遍序,分别取两次的最大-最小,然后再将这两次最大-最小取max;
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define ll long long using namespace std; int n,x,y; int a,b,c,d; int main(){ scanf("%d",&n); a=-0x7fffffff; b=0x7fffffff; c=-0x7fffffff; d=0x7fffffff; for(int i=1;i<=n;i++){ scanf("%d%d",&x,&y); a=max(x+y,a); b=min(b,x+y); c=max(x-y,c); d=min(x-y,d); } printf("%d",max(a-b,c-d)); return 0; }View Code
先只解决一次询问:
M[a][b]表示从a城市到b城市总共的路径条数;
f[i][j]表示走i步走到j的方案数;
那么:
最终答案是f[d][v];
但是非常不幸,复杂度O(n2d),你爆炸了;
优化?
我们把M看做一个n*n的矩阵,然后f[i]看做一个1*n的矩阵,那么f[i]=f[i-1]*M;
运用矩阵快速幂:
现在复杂的是O(N3logd),还是爆炸了;
考虑继续优化;
看k的数据范围,非常扎眼了也是
考虑是不是可以把复杂度优化成与k有关的:
考虑到交换顺序并不会影响计算,因此转化为:
定睛一看:
!矩阵乘法
然后我们也可以把out和in看成两个矩阵了
M=out*in;
然后我们的复杂度就只有O(k3logd)了
给你一颗n个点的树点权:a1,a2,a3,a4……an < int
M次询问:给出两点p1,p2,
能不能在p1,p2的路径上找出三个点,使三个点的点权使之组成一个三角形;
n,M<=1e6;
写下点权,然后从小到大排序,不能组成三角形的情况:a3>=a1+a2,a4>=a2+a3,……an>=an-2+an-1;
如果恰好取等,刚好为斐波那契数列(不能组成三角形的最小(极限)情况),然后因为所有数都不爆int,所以当序列长度>斐波那契数列爆int项的项数时,显然是yes,否则直接暴力??
标签:int,ll,石子,讲题,7.19,y1,include,质数 来源: https://www.cnblogs.com/zhuier-xquan/p/11211111.html