NOIP模拟 17.8.20
NOIP模拟17.8.20
A.阶乘
【题目描述】
亲爱的xyx同学正在研究数学与阶乘的关系,但是他喜欢颓废,于是他就制作了一个和阶乘有关系的数学游戏:
给出两个整数 n,m,令 t = !n,每轮游戏的流程如下
1.如果 m不能整除t ,即 t mod m ≠ 0,跳到第三步;如果能整除,跳到第二步
2.令 t = t/m,xyx的得分+1并返回第一步
3.游戏结束
xyx共进行T轮游戏,他想知道每轮他的得分是多少
【输入描述】
第一行一个整数 T,表示游戏轮数
接下来 T行,每行两个正整数n,m ,含义见题目描述
【输出描述】
共T 行,每行输出一个整数,表示xyx该轮游戏得到的分数
【样例输入】
4
2 3
3 3
23456 5
8735373 10
【样例输出】
0
1
5861
2183837
【限制与约定】
对于30% 的数据, n,m ≤ 20
对于60% 的数据, n,m ≤ 1e6
对于 100%的数据, n,m ≤ 1e9 ,T ≤ 10,1 < m <= 15
【题解】
此题极好
n! = 1*2*3*4*5*...*n
把m分解,设第i个质因数为pi,假设n中有k个pi
n! = 1*2*3..*pi*...*2pi*...*3pi*...*kpi...*n
然后我们让n/=pi,可以得到
n/pi! = 1*2*3*...*pi*...*2pi*...*3pi*...*(k - n/p - 1)pi*...*n/pi
证明比较显然,k*p每次-p就到达下一个p的倍数,于是,n每次-p,(n-p)!就
少一个p。干脆直接n不断/p就好了
最终结果要除以m中pi的数量
取一个min即可
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define min(a, b) ((a) < (b) ? (a) : (b)) inline void read(long long &x)
{
x = ;char ch = getchar(), c = ch;
while(ch < '' || ch > '')c = ch, ch = getchar();
while(ch <= '' && ch >= '')x = x * + ch - '', ch = getchar();
if(c == '-')x = -x;
} const long long INF = 0x3f3f3f3f; long long n,m,t,ans; int main()
{
read(t);
register long long k,tmp,p;
for(;t;--t)
{
read(n), read(m);
ans = INF;
for(register int i = ;i <= m;++ i)
{
if(m % i == )
{
k = , p = n, tmp = ;
while(m % i == )m /= i, ++ k;
while(p)tmp += p/i, p/= i;
ans = min(ans, tmp/k);
}
}
printf("%I64d\n", ans);
}
return ;
}
T1
B.妹子
【题目描述】
亲爱的xyx同学正在研究数学与妹子的关系,但是他喜欢颓废,于是他就制作了一个和妹子有关系的数学游戏:
有一棵树,树上每个点i 有一个权值ai ,每轮游戏中xyx和妹子会各自选择一个点,然后对于树上所有的点来说,如果它与
xyx所选点的距离更近,那么xyx就会得到等于该点权值的分数;如果它与妹子所选点的距离更近,那么妹子就会得到等
于该点权值的分数;如果距离相等,那么xyx和妹子都不会得到分数。
xyx想知道,每轮游戏中,他和妹子得到的分数分别是多少
两点间的距离定义为该两点最短路径所经过的边的权值之和
【输入描述】
第一行一个整数 n,表示树的顶点数。
接下来n -1行,每行两个整数 u,v,w,表示第i 条边连接点 u,v,边权为w
接下来一行共 n个整数,表示树上每个点 i的权值ai 。
接下来一行一个整数 m,表示游戏轮数
接下来 m行,每行两个整数x,y ,分别表示xyx所选的点和妹子所选的点
【输出描述】
共 m行,每行输出两个整数,表示xyx得到的分数和妹子得到的分数,中间用一个空格隔开。
【样例输入】
3
1 2 1
1 3 1
10 1 1
2
2 3
1 3
【样例输出】
1 1
11 1
【限制与约定】
对于10% 的数据, n,m ≤ 100
对于30%的数据, n,m ≤ 1000
对于另外15% 的数据,第 i条边连接点i,i+1
对于另外15% 的数据,树和询问保证随机生成
对于 100%的数据,n ≤ 100000,m ≤ 50000,1 ≤ x, y,u, v ≤ n,1 ≤ w,ai ≤ 10
【题解】
此题极好+1
考察细节,参见代码
“点的类型可以看成是单调的(属于x->谁都不属于->属于y)
设dis[x]表示x到根的距离,每次询问中dis[x]>dis[y],他们的lca为p
那么点的类型边界一定在p->x的路径上
由于在链上存在单调性,可以二分+倍增找深度差为k的父亲来做
复杂度O(n log^2 n)
也可以倍增+从高到低确定二进制位,这一位是1时如果已经不受x控制,则这一位一定为0;反之这一位为0(贪心思路)
复杂度O(n log n)”
——张浩南
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring> inline void read(long long &x)
{
x = ;char ch = getchar(),c = ch;
while(ch < '' || ch > '')c = ch, ch = getchar();
while(ch <= '' && ch >= '')x = x * + ch - '', ch = getchar();
if(c == '-')x = -x;
} const long long MAXN = + ; struct Edge
{
long long u,v,next,w;
Edge(long long _u, long long _v, long long _next, long long _w){u = _u;v = _v;next = _next;w = _w;}
Edge(){}
}edge[MAXN << ]; long long n,m,b[MAXN],value[MAXN],sum[MAXN],path[MAXN],p[][MAXN],deep[MAXN],fa[MAXN],head[MAXN],cnt; inline void insert(long long a, long long b, long long c)
{
edge[++cnt] = Edge(a,b,head[a],c);
head[a] = cnt;
} void dfs(long long u)
{
b[u] = ;
sum[u] = value[u];
for(register long long pos = head[u];pos;pos = edge[pos].next)
{
long long v = edge[pos].v;
if(b[v])continue;
path[v] = path[u] + edge[pos].w;
deep[v] = deep[u] + ;
dfs(v);
fa[v] = u;
p[][v] = u;
sum[u] += sum[v];
}
} //p[0]是点 p[1]是路径长度
inline void yuchuli()
{
long long M = ;
while(( << M) <= n)++ M;
-- M;
for(register long long i = ;i <= M;++ i)
for(register long long j = ;j <= n;++ j)
p[i][j] = p[i - ][p[i - ][j]];
} long long lca(long long va, long long &vb)
{
int flag = ;
if(deep[va] < deep[vb])
{
long long tmp = va;
va = vb;
vb = tmp;
flag = ;
}
long long M = ;
while(( << M) + deep[vb] <= deep[va])++ M;
-- M;
for(register long long i = M;i >= ;-- i)
if(( << i) + deep[vb] <= deep[va])
va = p[i][va];
if(va == vb)return va;
M = ;
while(( << M) + deep[vb] <= n)++ M;
-- M;
for(register long long i = M;i >= ;-- i)
if(p[i][va] != p[i][vb])
{
va = p[i][va];
vb = p[i][vb];
}
if(flag)vb = va;
return p[][va];
} int main()
{
read(n);
register long long tmp1, tmp2, tmp3;
for(register long long i = ;i < n;++ i)
{
read(tmp1),read(tmp2),read(tmp3);
insert(tmp1, tmp2, tmp3);
insert(tmp2, tmp1, tmp3);
}
for(register long long i = ;i <= n;++ i) read(value[i]);
deep[] = ;
dfs();
yuchuli();
read(m);
register long long a,b,ans1,ans2,lenth,sa,sb,c,ok,M = ;
while(( << M) <= n)++ M;
-- M;
for(register long long i = ;i <= m;++ i)
{
read(a),read(b);
if(a == b)
{
printf("0 0\n");
continue;
}
ok = ;
if(path[a] < path[b])
{
int tmp = a;
a = b;
b = tmp;
ok = ;
}
sa = a, sb = b;
c = lca(sa, sb);
ans1 = ans2 = ;
/* if(c != 0)*/
lenth = path[a] + path[b] - (path[c] << );
/* else
lenth = path[a] - path[b];*/
for(register int i = M;i >= ;-- i)
if(((path[a] - path[p[i][sa]]) * ) < lenth)
sa = p[i][sa];
if(((path[a] - path[p[][sa]]) << ) == lenth)
{
if(p[][sa] == c)
{
if(ok)
printf("%lld %lld\n", sum[sb], sum[sa]);
else
printf("%lld %lld\n", sum[sa], sum[sb]);
continue;
}
else
{
if(ok)
printf("%lld %lld\n", sum[] - sum[fa[sa]], sum[sa]);
else
printf("%lld %lld\n", sum[sa], sum[] - sum[fa[sa]]);
continue;
}
}
else
{
if(ok)
printf("%lld %lld\n", sum[] - sum[sa], sum[sa]);
else
printf("%lld %lld\n", sum[sa], sum[] - sum[sa]);
continue;
}
}
return ;
}
T2
这题我调了很久,最后发现我本以为最不可能错的LCA居然写挂了,其他地方都没错。。。
C.在
【题目描述】
亲爱的xyx同学正在研究数学与存在的关系,但是他喜欢颓废,于是他就制作了一个和存在有关系的数学游戏:
有一个集合,游戏开始时里面有一些数,xyx每次可以选择集合中的两个数(这两个数可以是同一个数)相减,然后把它
们差的绝对值放入集合中(如果集合中已存在该数则不放入),经过任意次这样的操作后,xyx会给出一个数字 k,问它
是否能存在在集合中,如果能,那么游戏成功,反之失败。
(换句话说,xyx想知道这样不断操作下去,是否能凑出数字 k)
xyx有一个数列 a,他每次会给出三个数 l,r,x,即把所有的ai(l ≤ i ≤ r) 放入集合中,并且想要知道当 k = x时游戏是否成功
有多组询问且询问之间相互独立,你可以认为每次询问后xyx就把游戏中的集合清空了
【输入描述】
第一行两个整数n 和 m,分别表示数字集合的大小和询问次数。
第二行共 n个整数,表示数列 a,第 i个数是 ai。
接下来 m行,每行三个整数 l,r,x,含义见题目描述
【输出描述】
共 m行,每行一个字符串,表示对应询问的答案,如果游戏成功输出”win”,反之输出”lose”。(不输出引号)
【样例输入】
7 5
3 6 4 2 7 1 8
1 2 3
3 7 0
3 4 2
3 4 5
2 3 3
【样例输出】
win
win
win
lose
lose
【限制与约定】
对于20% 的数据, ai,x ∈ [0,1]
对于另外20% 的数据,保证 ai 随机生成
对于另外 20%的数据, l = 1
对于100% 的数据, n,m ≤ 100000,0 ≤ x,ai ≤ 10 ,1 ≤ l ≤ r ≤ n
【题解】
此题一般
当时场外试了几组数据,然后就看出来了
其实能不能凑出k,取决于两个条件:
1、数列中存在大于等于k的数
2、数列的gcd为k的因数
很显然,数列每个数都可以写作p*gcd的性质,他们加减,仍是p*gcd
每次写st表都要手推。。。所以注释里保存了我手推的过程,便于大家学习。。。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define max(a, b) ((a) > (b) ? (a) : (b)) inline void read(int &x)
{
x = ;char ch = getchar(),c = ch;
while(ch < '' || ch > '')c = ch, ch = getchar();
while(ch <= '' && ch >= '')x = x * + ch - '', ch = getchar();
if(c == '-')x = -x;
} const int MAXN = + ; /*
data[i][j]表示区间[j, j + 2^i - 1]
data[i][j] = gcd(data[i - 1][j], data[i - 1][j + 2^(i - 1)]
[j, j + 2^(i - 1) - 1] [j + 2 ^ (i - 1), j + 2^ i - 1] [l,r]
2 ^ M <= r - l + 1 < 2 ^ (M + 1)
data[M][l], data[M][r - 2^M + 1]
*/
int n,m,num[MAXN],data[][][MAXN],lo[MAXN],pow2[]; inline int gcd(int a, int b)
{
return b == ? a : gcd(b, a % b);
} inline void yuchuli()
{
int M = lo[n];
for(register int i = ;i <= M;++ i)
for(register int j = ;j <= n;++ j)
{
data[][i][j] = gcd(data[][i - ][j], data[][i - ][j + pow2[i - ]]);
data[][i][j] = max(data[][i - ][j], data[][i - ][j + pow2[i - ]]);
}
} int findma(int l, int r)
{
return max(data[][lo[r - l + ]][l], data[][lo[r - l + ]][r - pow2[lo[r - l + ]] + ]);
} int findgcd(int l, int r)
{
return gcd(data[][lo[r - l + ]][l], data[][lo[r - l + ]][r - pow2[lo[r - l + ]] + ]);
} int main()
{
read(n);read(m);
lo[] = ;
for(register int i = ;i <= n;++ i)lo[i] = lo[i >> ] + ;
pow2[] = ;
for(register int i = ;i <= ;++ i)pow2[i] = pow2[i - ] << ;
for(register int i = ;i <= n;++ i)read(num[i]), data[][][i] = data[][][i] = num[i];
yuchuli();
register int l,r,k;
for(register int i = ;i <= m;++ i)
{
read(l),read(r),read(k);
int ma = findma(l, r);
if(ma < k)
{
printf("lose\n");
continue;
}
int g = findgcd(l, r);
if(g == ) printf("win\n");
else if(k % g == )
{
printf("win\n");
continue;
}
else
{
printf("lose\n");
continue;
}
}
return ;
}
T3
NOIP模拟 17.8.20的更多相关文章
- NOIP模拟17.9.21
NOIP模拟17.9.21 3 58 145 201 161.5 样例输出21.6 数据规模及约定对于40% 的数据,N <= 20对于60% 的数据,N <= 1000对于100% 的数 ...
- NOIP模拟17.9.22
NOIP模拟17.9.22 前进![问题描述]数轴的原点上有一只青蛙.青蛙要跳到数轴上≥
- NOIP模拟 17.8.18
NOIP模拟17.8.18 A.小菜一碟的背包[题目描述]Blice和阿强巴是好朋友但萌萌哒Blice不擅长数学,所以阿强巴给了她一些奶牛做练习阿强巴有 n头奶牛,每头奶牛每天可以产一定量的奶,同时也 ...
- NOIP模拟 17.8.15
NOIP模拟17.8.15 A 债务文件名 输入文件 输出文件 时间限制 空间限制debt.pas/c/cpp debt.in debt.out 1s 128MB[题目描述]小 G 有一群好朋友,他们 ...
- NOIP模拟 17.8.16
NOIP模拟17.8.16 A 债务文件名 输入文件 输出文件 时间限制 空间限制debt.pas/c/cpp debt.in debt.out 1s 128MB[题目描述]小 G 有一群好朋友,他们 ...
- NOIP模拟 17.8.14
NOIP模拟17.8.14 (天宇哥哥考察细心程度的题) [样例解释]如果删去第一个 1:在[3,1,2]中有 3 个不同的数如果删去 3:在[1,1,2]中有 2 个不同的数如果删去第二个 1:在[ ...
- NOIP模拟 17.8.17
NOIP模拟17.8.17 A 小 G 的字符串文件名 输入文件 输出文件 时间限制 空间限制str.pas/c/cpp str.in str.out 1s 128MB[题目描述]有一天,小 L 给小 ...
- NOIP模拟 17.9.28
公交车[问题描述]市内有
- Noip模拟17 2021.7.16
我愿称这场考试为STL专练 T1 世界线 巧妙使用$bitset$当作vis数组使用,内存不会炸,操作还方便,的确是极好的. 但是这个题如果不开一半的$bitset$是会炸内存的,因为他能开得很大,但 ...
随机推荐
- @Restcontroller与@controller区别
@RestController注解相当于@ResponseBody + @Controller合在一起的作用. 1)如果只是使用@RestController注解Controller,则Control ...
- 搭建一个Semantic-ui项目
一.进入到项目目录 npm init 二.安装semantic-ui npm install semantic-ui --save 三.编译输出semantic-ui cd ./semantic g ...
- Inoic 滚动条问题
1.看图说话 2.没有超过一个页,怎样去掉图中的滚动条? 3修改后预览效果
- 20191004-gugugu公告
作者洗手不干了,所以以后可能会不写考试反思而是要写题解了…… ××这是$Day7$,于是我跪了 (不会,于是准备自己$YY$) 加油啊$LNC$你一定能$AK$的(雾 但是他因为太愧疚而没有打症结而是 ...
- linux学习(一)-----vm、centos安装
安装vm和Centos 1)先安装 virtual machine ,vm12 2)再安装 Linux (CentOS 6.8) 3)原理示意图,这里我们画图说明一下 VM 和 CentOS 的关系. ...
- HDFS命名空间管理
- js 高亮显示关键字
示例: var defaultEmphasisHandler = function(keyword, data){ var regex = RegExp("("+keyword.r ...
- iBaties对比hibernate
翻译至一篇2008年的文章(http://www.javaworld.com/article/2077875/open-source-tools/ibatis--hibernate--and-jpa- ...
- java并发系列(七)-----ConcurrentHashMap原理分析(JDK1.8)
JDK1.8的实现已经摒弃了Segment的概念,而是直接用Node数组+链表+红黑树的数据结构来实现,并发控制使用Synchronized和CAS来操作,整个看起来就像是优化过且线程安全的HashM ...
- java验证码识别
首先参考了csdn大佬的文章,但是写的不全ImgUtils类没有给出代码,无法进行了 写不完整就是制造垃圾 不过这个大佬又说这个大佬的文章值得参考于是又查看这篇文章 有案例https://blog.c ...