(File IO): input:forging.in output:forging.out
Time Limits: 1500 ms
Memory Limits: 262144 KB
勇者虽然武力值很高,但在经历了多次战斗后,发现怪物越来越难打
于是开始思考是不是自己平时锻炼没到位,于是苦练一个月后发现…自己连一个史莱姆都打不过了。
勇者的精灵路由器告诉勇者其实是他自己的武器不好,并把他指引到了锻造厂。
“欢迎啊,老朋友。”
一阵寒暄过后,厂长带他们参观了厂子四周,并给他们讲锻造的流程。
“我们这里的武器分成若干的等级,等级越高武器就越厉害,并且对每一等级的武器都有两种属性值 b 和 c,但是我们初始只能花 a 个金币来生产 1 把 0 级剑…”
“所以你们厂子怎么这么垃圾啊,不能一下子就造出来 999 级的武器吗?”勇者不耐烦的打断了厂长的话。
“别着急,还没开始讲锻造呢…那我们举例你手中有一把 x 级武器和一把 y 级武器 ( y = max ( x − 1 , 0 ) y =\max(x − 1, 0) y=max(x−1,0)),我们令锻造附加值 k = min ( c x , b y ) k=\min(c_x,b_y) k=min(cx,by),则你有 k c x \frac{k}{c_x} cxk的概率将两把武器融合成一把 x + 1 x+1 x+1级的武器。”
“…但是,锻造不是一帆风顺的,你同样有 1 − k c x 1−\frac{k}{c_x} 1−cxk 的概率将两把武器融合成一把 max ( x − 1 , 0 ) \max(x − 1, 0) max(x−1,0)级的武器…”
勇者听完后暗暗思忖,他知道厂长一定又想借此机会坑骗他的零花钱,于是求助这个村最聪明的智者——你,来告诉他,想要强化出一把 n 级的武器,其期望花费为多少?
由于勇者不精通高精度小数,所以你只需要将答案对 998244353 998244353 998244353( 7 × 17 × 2 23 + 1 7 ×17 × 2^{23} + 1 7×17×223+1,一个质数 ) 取模即可。
第一行两个整数 n, a,含义如题所示。
为了避免输入量过大,第二行五个整数 bx, by, cx, cy, p,按照下列代码
来生成 b 和 c 数组。
b[0]=by+1;c[0]=cy+1;
for(int i=1;i<n;i++){
b[i]=((long long)b[i-1]*bx+by)%p+1;
c[i]=((long long)c[i-1]*cx+cy)%p+1;
}
输出一行一个整数,表示期望花费。
Sample Input1
0 6432
4602677 3944535 2618884 6368297 9477531
Sample Input2
1 3639650
6136976 5520115 2835750 9072363 9302097
Sample Input3
10 2
2 33 6 66 2333333
Sample Input4
200 5708788
0 0 0 0 1
Sample Output1
6432
Sample Output2
150643649
Sample Output3
976750710
Sample Output4
696441597
测试点 | n ≤ n\leq n≤ | 特殊性质 |
---|---|---|
1 | 0 0 0 | N / A N/A N/A |
2 | 1 1 1 | N / A N/A N/A |
3 | 200 200 200 | 有 |
4 | 200 200 200 | N / A N/A N/A |
5 | 2000 2000 2000 | 有 |
6 | 2000 2000 2000 | N / A N/A N/A |
7 | 1 0 6 10^6 106 | 有 |
8 | 1 0 6 10^6 106 | N / A N/A N/A |
9 | 1 0 7 10^7 107 | 有 |
10 | 1 0 7 10^7 107 | N / A N/A N/A |
对于特殊性质处标示为“有”的数据满足 p = 1。
对于 100% 的数据, 0 ≤ a ≤ 1 0 7 0 ≤ a ≤ 10^7 0≤a≤107 , 0 ≤ b x , b y , c x , c y < p < 1 0 7 0 ≤ bx, by, cx, cy < p < 10^7 0≤bx,by,cx,cy<p<107 , 0 ≤ n ≤ 1 0 7 0 ≤ n ≤10^7 0≤n≤107
(File IO): input:division.in output:division.out
Time Limits: 3000 ms
Memory Limits: 262144 KB
整除符号为 |,d|n 在计算机语言中可被描述为 n%d == 0。
现有一算式 n ∣ x m − x n|x^m - x n∣xm−x,给定 n,m,求 [1, n] 以内 x 解的个数。
解可能很大,输出取模 998244353。
其中 n 的给定方式是由 c 个不超过 t 的质数的乘积给出的,c 和 t 的范围会在数据范围中给出。
第一行一个 id 表示这个数据点的标号。
多组数据,其中第二行一个整数 T 表示数据组数。对于每一组数据:
第一行两个整数 c 和 m。
第二行 c 个整数,这些整数都是质数,且两两不同,他们的乘积即为n。
由于你可以通过输入求出 n,输入不再给出。
对于每组数据输出一行,表示解的个数。
0
1
2 3
2 3
6
另有两个样例,见下发文件。
(File IO): input:money.in output:money.out
Time Limits: 1000 ms
Memory Limits: 524288 KB
南极的企鹅王国大学中生活着 n 只企鹅,作为 21 世纪的优秀大学生,企鹅们积极响应“大众创业,万众创新”的号召,纷纷创业。但是创业需要资金,企鹅们最近手头比较紧,只能互相借钱。
企鹅的借钱行为是有规律可循的:每只企鹅只会借一次钱,并且只会从一只企鹅那里借钱。借钱关系中不存在环(即不存在类似“金企鹅欠银企鹅钱,银企鹅欠铜企鹅钱,铜企鹅欠金企鹅钱”这种情况)。
企鹅的还钱行为也是有规律可循的:每只企鹅一旦新获得了一笔钱,就会立刻用这笔钱尽可能偿还自己欠的债务,直到债务偿清或用光这笔钱。它只会使用新获得的这笔钱,至于以前它有没有钱、有多少钱,与还钱行为无关。
企鹅们经常会做美梦。在一只企鹅 A 的梦里,它梦见自己创业成功,一下子获得了 +∞ 元钱,于是(按照上文的还钱规则)它赶快把钱用来还债,接着拿到钱的那只企鹅也赶快把钱用来还债…如此往复,直到所有获得钱的企鹅都完成了还债操作。梦醒之后,它开心地把梦的内容告诉了另外一只企鹅 B,企鹅 B 听了,也很开心,于是它问道:在你的梦里,我获得了多少钱呢?(指 B 去还债之前手里的钱,包括后来用于还债的钱和还债后B 手里剩下的钱。)
梦毕竟是梦,对实际的欠债情况没有影响。
第一行两个整数 n 和 m,表示有 n 只企鹅,m 个操作。
接下来 m 行,有两种可能的格式:
本题强制在线,也就是说:对于每个操作输入的变量 a, b, c(如果没有c,那就只有 a, b)都不是实际的 a, b, c,想获得实际的 a, b, c 应当经过以下操作:
a = (a + lastans) % n + 1;
b = (b + lastans) % n + 1;
c = (c + lastans) % n + 1;
其中,lastans 是上一次询问的答案。如果没有上一次询问,lastans 为0。
对每个询问操作,输出一行一个数表示答案。
5 9
0 1 2 1
0 0 1 2
1 0 1
1 2 4
0 2 1 1
1 2 0
0 3 1 0
1 4 2
1 3 4
3
2
0
1
0
数据分为以下几种:
第一种:占 10%,n ≤ 5000 且 m ≤ 10000;
第二种:占 20%,所有借钱事件(0 开头的操作)发生在所有询问事件(1 开头的操作)之前;
第三种:占 30%,对于一只企鹅 A,最多只有一只企鹅向 A 借钱;
第四种:占 40%,没有特殊性质,n、m 大小有一定梯度。
对于所有数据,满足: n ≤ 1 0 5 , m ≤ 1 0 6 , 0 ≤ a , b , c ≤ n n ≤ 10^5 ,m ≤ 10^6 ,0 ≤ a, b, c ≤ n n≤105,m≤106,0≤a,b,c≤n 且 a ≠ b a \neq b a̸=b。
今天的题目真是神仙~。
比赛时看了每一道题,感觉T3最可做。
- 我用了一个并查集维护每一个点属于哪一个集合,如果加入一条x到y的边,那么把x的集合并入y的集合。
- 查询的时候路径压缩一下,对于每一个在此过程中经过的点,都更新一下倍增数组和深度。 此时对于一组询问(x,y),如果x可以影响到y,那么x到y的路径一定是一条链,因此我们只要从x开始往 d e p t h y depth_y depthy的深度跳。
- 最后如果x走到 d e p t h y depth_y depthy的深度都不与y重合,输出0;否则答案就是一路上的边权最小值。
这个方法看起来可以AC,但是我并没有对此抱有太大信心,因为旁边的张JJ大佬一直在自言自语:“T3是Link Cut Tree。”但是我并没有举出范例,于是就这么打了。
打完T3后,我转眼看向T1、T2。T1我设 f i f_i fi表示锻造出 i 级武器的期望花费,结果发现锻造失败的情况会无限循环 虽然一个勇者的运气不会那么背,不然早就被史莱姆KO了 ,手足无措。最后只处理了n=0的情况,10分。
T2化出了一条 x m − 2 ≡ x − 1 ( m o d    n ) x^{m-2}\equiv x^{-1}\quad(\mod n) xm−2≡x−1(modn)的式子费马小定理?,搞了半天都不知道这是什么蘑菇,于是放弃,打暴力。
最后得分:10+20+30=60 好整齐啊
T3怎么没有100?神奇的是,我似乎通过了前30%的数据点!
我于是想了一个午饭的时间,发现 吃饭时思考效率明显提高 这样做并不能更新所有倍增时走到的点,那么甚至连depth数组都不满足单调性,还倍增个什么!
于是我沮丧地点开了题解,发现了三个字母:LCT。然后我就更加沮丧了
原来LCT只是一种解法,还有一种解法,很像我的水法。
- 我们可以用倍增求出链上的最小值,关键在于怎么维护倍增数组。
- 可以开一个无向无根树,每一次加边的时候就把两棵树启发式合并,就是把节点数少的那一棵接到节点数多的那一棵树上。接着暴力修改节点数少的那一棵树上的所有节点,修改它们的倍增数组和深度。时间复杂度 O ( n log 2 2 n ) O(n\log_2^2n) O(nlog22n)
- 那么怎么查询呢?在树上我们还维护一个记录方向的倍增数组,如果一条链上所有点都是从儿子到父亲,那么方向为2;如果是父亲到儿子,方向为1;如果两者都有,就为3( 3 = 1 ∣ 2 3=1|2 3=1∣2)
- 最后把查询的两个点求lca,如果经过的链方向不对,那么输出0。
- 时间复杂度 O ( n log 2 2 n + m log 2 n ) O(n\log_2^2n+m\log_2n) O(nlog22n+mlog2n)
T1并没有我想象中的那么难,还是设 f i f_i fi表示锻造出 i 级武器的期望花费。如果锻造失败,就会得到一个 max ( i − 2 , 0 ) \max(i-2,0) max(i−2,0)级的武器,那么我们在重新锻造一把 i 级武器时就不用 max ( i − 2 , 0 ) \max(i-2,0) max(i−2,0)级的武器了。
于是可以列出状态转移方程(令 p = min ( c i − 1 , b max ( i − 2 , 0 ) ) c i − 1 p=\cfrac{\min\left(c_{i-1},b_{\max(i-2,0)}\right)}{c_{i-1}} p=ci−1min(ci−1,bmax(i−2,0))):
f i = f i − 1 + f max ( i − 2 , 0 ) + ( 1 − p ) ( f i − f max ( i − 2 , 0 ) ) f i = f i − 1 + f max ( i − 2 , 0 ) + f i − f max ( i − 2 , 0 ) − p ⋅ f i + p ⋅ f max ( i − 2 , 0 ) p ⋅ f i = f i − 1 + p ⋅ f max ( i − 2 , 0 ) f i = f i − 1 p + f max ( i − 2 , 0 ) f i = f i − 1 ⋅ c i − 1 ⋅ min ( c i − 1 , b max ( i − 2 , 0 ) ) − 1 + f max ( i − 2 , 0 ) \begin{aligned} f_i&=f_{i-1}+f_{\max(i-2,0)}+(1-p)(f_i-f_{\max(i-2,0)})\\ f_i&=f_{i-1}+f_{\max(i-2,0)}+f_i-f_{\max(i-2,0)}-p\cdot f_i+p\cdot f_{\max(i-2,0)}\\ p\cdot f_i&=f_{i-1}+p\cdot f_{\max(i-2,0)}\\ f_i&=\frac{f_{i-1}}{p}+f_{\max(i-2,0)}\\ f_i&=f_{i-1}\cdot c_{i-1}\cdot \min\left(c_{i-1},b_{\max(i-2,0)}\right)^{-1}+f_{\max(i-2,0)} \end{aligned} fifip⋅fififi=fi−1+fmax(i−2,0)+(1−p)(fi−fmax(i−2,0))=fi−1+fmax(i−2,0)+fi−fmax(i−2,0)−p⋅fi+p⋅fmax(i−2,0)=fi−1+p⋅fmax(i−2,0)=pfi−1+fmax(i−2,0)=fi−1⋅ci−1⋅min(ci−1,bmax(i−2,0))−1+fmax(i−2,0)
那么为什么不用把 f i − 1 + f max ( i − 2 , 0 ) f_{i-1}+f_{\max(i-2,0)} fi−1+fmax(i−2,0)乘上p呢?第二天我吃早餐的时候想明白了,说明吃饭时思考效率明显提高 因为无论成功与否,我们都要用 i − 1 i-1 i−1级和 max ( i − 2 , 0 ) \max(i-2,0) max(i−2,0)级的两把武器,只是失败后还要额外浪费一把 i − 1 i-1 i−1级。
然后就可以轻松地AC了懵逼地TLE了。
以下是各种玄学优化:
inv[1]=1;
for(i=2;i<=p+1;i++) inv[i]=1LL*inv[mod%i]*(mod-mod/i)%mod;
#pragma GCC optimize("Ofast")
#pragma GCC target("sse3","sse2","sse")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#pragma GCC diagnostic error "-std=c++14"
由于题目已经给出了 n = p 1 ⋅ p 2 ⋅ p 3 ⋯ p c n=p_1\cdot p_2\cdot p_3\cdots p_c n=p1⋅p2⋅p3⋯pc, n ∣ x m − x n|x^m-x n∣xm−x,所以 p i ∣ x m − x ( i ∈ [ 1 , c ] , x ∈ [ 1.. n ] ) p_i|x^m-x(i\in[1,c],x\in[1..n]) pi∣xm−x(i∈[1,c],x∈[1..n])
显然答案就是每个这样的同余方程的解的数量+1的乘积。
于是就可以暴力了。
但是暴力又要卡常。。。十分麻烦。
我好不容易AC后,发现了一种清爽的求法: a n s = ∏ i = 1 c g c d ( p i − 1 , m − 1 ) + 1 ans=\prod_{i=1}^cgcd(p_i-1,m-1)+1 ans=i=1∏cgcd(pi−1,m−1)+1
证明在此:https://www.cnblogs.com/ImagineC/p/9880891.html
总结:这次比赛反映了我对期望等数学知识的不熟悉,应加强!
#include
using namespace std;
#pragma GCC optimize("Ofast")
#pragma GCC target("sse3","sse2","sse")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#pragma GCC diagnostic error "-std=c++14"
#define mod 998244353
#define N 10000005
int f[2],b[2],c[2],inv[N];
inline int min(int x,int y){return x<y?x:y;}
int main()
{
freopen("forging.in","r",stdin);
freopen("forging.out","w",stdout);
register int n,a,bx,by,cx,cy,p,i,i_1=0,i_2=1;
scanf("%d%d%d%d%d%d%d",&n,&a,&bx,&by,&cx,&cy,&p);
b[0]=by+1,c[0]=cy+1,f[0]=a,inv[1]=1;
for(i=2;i<=p+1;i++) inv[i]=1LL*inv[mod%i]*(mod-mod/i)%mod;
for(i=1;i<=n;i++,i_1^=1,i_2^=1)
{
f[i_2]=(f[i<2?i_1:i_2]+1LL*f[i_1]*c[i_1]%mod*inv[min(c[i_1],b[i<2?i_1:i_2])])%mod;
b[i_2]=(1LL*b[i_1]*bx%p+by)%p+1;
c[i_2]=(1LL*c[i_1]*cx%p+cy)%p+1;
}
printf("%d\n",f[i_1]);
return 0;
}
#pragma GCC optimize("Ofast")
#pragma GCC target("sse3","sse2","sse")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#pragma GCC diagnostic error "-std=c++14"
#include
using namespace std;
#define mod 998244353
#define N 10005
int prime[N],pow[N],fac[N][2],m,id;
bool b[N];char buf[500005],ch;
inline char gc()
{
static char *p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,500005,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x)
{
while(ch=gc(),ch<'0'||ch>'9');x=ch-'0';
while(ch=gc(),ch>='0'&&ch<='9') x=x*10+ch-'0';
}
inline int power(int x,int P)
{
int s=1,y=m;
while(y)
{
if(y&1) s=s*x%P;
x=x*x%P,y>>=1;
}
return s;
}
int main()
{
freopen("division.in","r",stdin);
freopen("division.out","w",stdout);
register int i,j,t,num,p,ans,cnt;
read(id),read(t);
for(i=2;i<N;i++)
{
if(!b[i]) prime[++prime[0]]=i;
for(j=1;j<=prime[0];j++)
{
if(i*prime[j]>=N) break;
b[i*prime[j]]=1;
fac[i*prime[j]][0]=prime[j],
fac[i*prime[j]][1]=i;
if(i%prime[j]==0) break;
}
}
while(t--)
{
read(num),read(m);
for(i=ans=1;i<=num;i++)
{
read(p);
for(j=cnt=1;j<=p;j++)
{
if(b[j])
pow[j]=pow[fac[j][0]]*pow[fac[j][1]]%p;
else pow[j]=power(j,p);
if(pow[j]==j) cnt++;
}
ans=1LL*ans*cnt%mod;
}
printf("%d\n",ans);
}
return 0;
}
#pragma GCC optimize("Ofast")
#pragma GCC target("sse3","sse2","sse")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#pragma GCC diagnostic error "-std=c++14"
#include
using namespace std;
#define mod 998244353
#define N 10005
char ch;
inline char gc()
{
static char buf[500005],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,500005,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x)
{
while(ch=gc(),ch<'0'||ch>'9');x=ch-'0';
while(ch=gc(),ch>='0'&&ch<='9') x=x*10+ch-'0';
}
inline long long gcd(int x,int y)
{
int r;
while(y)
r=x%y,x=y,y=r;
return x+1;
}
int main()
{
freopen("division.in","r",stdin);
freopen("division.out","w",stdout);
register int m,id,t,num,p,ans;
read(id),read(t);
while(t--)
{
read(num),read(m),ans=1;
while(num--)
read(p),ans=1LL*ans*gcd(p-1,m-1)%mod;
printf("%d\n",ans);
}
return 0;
}
#include
using namespace std;
#pragma GCC optimize("Ofast")
#pragma GCC target("sse3","sse2","sse")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#pragma GCC diagnostic error "-std=c++14"
#define swap(x,y) x^=y,y^=x,x^=y
#define N 100005
struct edge{int end,len,dir,nex;}a[N<<1];//1:x->y 2:y->x
int fa[N],dep[N],siz[N],fir[N],f[N][17],min[N][17],dir[N][17],n,m,ans,cnt;
char ch;//1:son->father 2:father->son
inline char gc()
{
static char buf[1000005],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000005,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x)
{
while(ch=gc(),ch<'0'||ch>'9');x=ch-'0';
while(ch=gc(),ch>='0'&&ch<='9') x=x*10+ch-'0';
}
inline int mymin(int x,int y){return x<y?x:y;}
inline void inc(int x,int y,int z)
{
a[++cnt]=(edge){y,z,1,fir[x]},fir[x]=cnt;
a[++cnt]=(edge){x,z,2,fir[y]},fir[y]=cnt;
}
void dfs(int k,int from,int num)
{
fa[k]=num,dep[k]=dep[from]+1;
for(int i=1;i<17;i++)
{
f[k][i]=f[f[k][i-1]][i-1];
min[k][i]=mymin(min[k][i-1],min[f[k][i-1]][i-1]);
dir[k][i]=dir[k][i-1]|dir[f[k][i-1]][i-1];
}
for(int i=fir[k];i;i=a[i].nex)
if(a[i].end!=from)
{
f[a[i].end][0]=k;
min[a[i].end][0]=a[i].len;
dir[a[i].end][0]=a[i].dir^3;
dfs(a[i].end,k,num);
}
}
inline void add(int x,int y,int z)
{
inc(x,y,z);
if(siz[fa[x]]>siz[fa[y]]) swap(x,y);
f[x][0]=y,min[x][0]=z,dir[x][0]=a[fir[x]].dir;
siz[fa[y]]+=siz[fa[x]];
dfs(x,y,fa[y]);
}
inline int qry(int u,int v)
{
if(fa[u]!=fa[v]) return 0;
int i,res=n,d=3;
if(dep[u]>dep[v]) swap(u,v),d=0;
for(i=16;i>=0;i--)
if(dep[f[v][i]]>=dep[u])
{
if(dir[v][i]!=(1^d)) return 0;
res=mymin(res,min[v][i]),v=f[v][i];
}
if(u==v) return res;
for(i=16;i>=0;i--)
if(f[v][i]!=f[u][i])
{
if(dir[v][i]!=(1^d)||dir[u][i]!=(2^d)) return 0;
res=mymin(res,mymin(min[v][i],min[u][i]));
v=f[v][i],u=f[u][i];
}
if(dir[v][0]!=(1^d)||dir[u][0]!=(2^d)) return 0;
return mymin(res,mymin(min[v][0],min[u][0]));
}
int main()
{
freopen("money.in","r",stdin);
freopen("money.out","w",stdout);
int i,j,x,y,z;
read(n),read(m);
for(i=1;i<=n;i++) fa[i]=i,dep[i]=siz[i]=1;
while(m--)
{
read(i),read(x),read(y);
x=(x+ans)%n+1,y=(y+ans)%n+1;
if(i) printf("%d\n",ans=qry(x,y));
else read(z),z=(z+ans)%n+1,add(x,y,z);
}
return 0;
}