2021.9.24
T1:money
Problem:
YLCH在BZ家打工,YLCH的总薪酬是一根单位长度为L的金条,而YLCH要为BZ工作L天,所以YLCH的日工资为单位长度为1的金条。
YLCH由于不满BZ的九九六工作制,于是他向BZ提出了一个要求:每天先给工资再干活!即工作第k天,他手上要有k单位长度的金条(不能多也不能少。
BZ答应了他,但很明显BZ要对金条进行切割,他想知道怎么切次数最少,他觉的太简单了于是把问题扔给了你。
Solution:
a[x]=2x-1 (x>=1)
a[i]即可组成1~2x 中任意数
Code:
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 int len,a[200],cnt; 5 inline void work(int x){ 6 int sum=0; 7 a[1]=1; 8 while(sum<=x){ 9 sum+=a[++cnt]; 10 a[cnt+1]=a[cnt]*2; 11 } 12 sum-=a[cnt]; 13 a[cnt]=x-sum; 14 if(a[cnt]==0) cnt--; 15 } 16 signed main(){ 17 scanf("%lld",&len); 18 work(len); 19 printf("%lld\n",cnt-1); 20 sort(a+1,a+cnt+1); 21 for(int i=1;i<=cnt;i++) printf("%lld\n",a[i]); 22 return 0; 23 }
T2:times
Problem:
数学奥赛的ZGY同学处于一个n×m的跑操队伍中,他发现队伍中所有的小姐姐位置(x,y)与他位置(1,1)的连线不经过任何一个人(也就是说他可以直接看到所有小姐姐且不被任何人遮挡),而他最近接触了数论,于是他自己YY了一道题打算用它搭讪小姐姐们,题如下:
给定质数 p,整数 k,求 : ∏(x=1~k) (x&1) ? 1 : φ(p) * inv((φ(p)-x)!) (mod p)
他想知道算式的结果,和他需要把这个题打印多少份使小姐姐们每人都有一份(自己没有
对于x!,x<0,虽然这种阶乘不存在(-1除外,-1有双阶乘,但与此题无关),但我们定义这种阶乘形式成立存在逆元形式(虽然没有实际意义,但你可以把他当做推导过程中的一个工具)。
Solution:
首先转换式子: ∏(x=1~k) (x&1) ? 1 : (p-1) * inv((p-1-x)!) (mod p)
很明显, 为奇数对答案没有贡献。暂时从中取出一个偶数 x 进行讨论。
? ≡ (p-1) * inv ((p-1-x)!) (mod p)
? * (p-1-x)! ≡ (p-1) (mod p)
? * (p-1-x)! ≡ -1 (mod p)
? * (p-1-x)! ≡ (p-1)! (mod p)
(∏(i=p-x~p-1) i) * (p-1-x)! ≡ (p-1)! (mod p)
? ≡ ∏(i=p-x~p-1) i ≡ ∏(i=1~x) (-i) ≡ ∏(i=1~x) i ≡ x! (mod p)
这样原式就转化为了 : ∏(x=1~k) (x&1) ? 1 : x! (mod p)
然后就可以线性求解了。
Code:
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 const int maxn=4e7+1; 5 int n,m,T,t,anss=2; 6 int p,k,num,res,ans; 7 int tot,mu[maxn],pri[maxn]; 8 bool v[maxn]; 9 inline void work(int n){ 10 mu[1]=1; 11 for(int i=2;i<=n;i++){ 12 if(!v[i]){ 13 mu[i]=-1; 14 pri[++tot]=i; 15 } 16 for(int j=1;j<=tot&&i*pri[j]<=n;j++){ 17 v[i*pri[j]]=1; 18 if(i%pri[j]==0) break; 19 mu[i*pri[j]]=-mu[i]; 20 } 21 } 22 } 23 signed main(){ 24 scanf("%lld%lld",&n,&m); 25 n--; 26 m--; 27 T=max(n,m); 28 t=min(n,m); 29 if(n==0&&m==0) cout<<"0"<<endl; 30 else if(n==0||m==0) cout<<"1"<<endl; 31 else{ 32 work(T); 33 for(int i=2;i<=T;i++) mu[i]=mu[i]+mu[i-1]; 34 for(int l=1,r;l<=t;l=r+1){ 35 r=min(n/(n/l),m/(m/l)); 36 anss+=(mu[r]-mu[l-1])*(n/l)*(m/l); 37 } 38 printf("%lld\n",anss); 39 } 40 scanf("%lld%lld",&p,&k); 41 if(p<=k) cout<<"0"<<endl; 42 else{ 43 ans=num=1; 44 for(int i=2;i<=k;i+=2){ 45 num=num*i%p*(i-1)%p; 46 ans=ans%p*num%p; 47 } 48 printf("%lld\n",ans); 49 } 50 return 0; 51 }
T3:number
Problem:
根据魔力衍生与转换定律,钢之炼金术师可以使用魔力值为 i 的光晶石和魔力值为 j 的暗晶石各一个来合成一块能被人类正常使用的魔力为 i * j 的魔能晶。一块魔能晶可以用于发射d(i*j)次魔导炮。
艾力亚尔国有魔力值分别为 1 到 n 的 n 种光晶石,每种有 m 个,有魔力值分别为 1 到 m 的 m 种暗晶石,每种有 n 个。
为了讨伐新魔王谢萨斯,艾力亚尔国将这些晶石库存全部转换为了魔能晶,现在为了更好地进行火力部署,国王想知道这些魔能晶一共可以发射多少次魔导炮,但晶石数量实在是太多,所以他找到了(转生逆天功成名就人生赢家)大贤者,也就是你。
一种光晶石和一种暗晶石只能被合成一次,比如这次光暗晶石配对能量为(1,1),之后就不能出现(1,1)的配对情况。
d(n)表示 n 的约数个数
Solution:
Σ(i=1~n) Σ(j=1~m) d(i*j)
传统的计算 d(n) 的方法,是通过计算所有的因数的组合情况,即 : d(n) = ∏(i=1) (ai+1)
但很明显他太慢了,没有什么良好的性质。
考虑上述式子的本质思想,就是通过组合若干个质因子合成一个新因数。
那我们是否可以换一种枚举方式?
我们做出以下约定,对于一个质因数 ps,as 为 x 中含有多少个 ps,bs 为 y 中含有多少个 ps。
之前,ps 的数量在 x,y 中任意选,但想一想,我们是否可以规定一个优先级,即对于一个质数 ps,先取 x 中的,x 中的取完了,再去取 y 中的。
这个思想貌似对应着一个合式:d(x*y) = Σ(i|x) Σ(j|y) [(i,j) = 1]
i,j 的强制互质保证了一个质因数 ps 只能在 i,j 中的一方出现,但注意,在 i 中选 k 个和在 j 中选 k 个的意义不同。i 中选 k 个表示 i 中选 k 个,j 中选 0 个;j 中选 k 个表示先把 i 中的 ps 选完,再在 j 中选 k 个,共选了 as+k 个。这样,不同质数分别组合出了 i , j , i*j,便是传统方法枚举出的一个因数,当然有些值会重复枚举,但意义不同。
Σ(i=1~n) Σ(j=1~m) d(i,j)
Σ(i=1~n) Σ(j=1~m) Σ(x|i) Σ(y|j) [(x,y)=1]
Σ(x=1~n) Σ(y=1~m) [(x,y)=1] (n/x) (m/y)
∑(x=1~n) ∑(y=1~m) (∑(d|x,d|y) μ(d)) (n/x) (m/y)
∑(d=1~min(n,m)) μ(d) ∑(x=1~n/d) ∑(y=1~m/d) (n/xd) (m/yd)
设整除分块函数f(n)=Σ(i=1~n) (n/i),代入
Σ(d=1~min(n,m)) μ(d) Σ(x=1~n/d) Σ(y=1~m/d) (n/xd) (m/yd)
Σ(d=1~min(n,m)) μ(d) f(n/d) f(m/d)
f(n)=Σ(i=1~n) (n/i) =Σ(i=1~n) d(i)
O(N)预处理 d,线筛即可,整体复杂度O(N)。
(注:除法自动向下取整)
Code:
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 const int maxn=1e7+1; 5 int n,m,t,ans,pri[maxn],cnt,mu[maxn],d[maxn],num[maxn]; 6 bool v[maxn]; 7 inline void work(){ 8 d[1]=mu[1]=1; 9 for(int i=2;i<maxn;i++){ 10 if(!v[i]){ 11 pri[++cnt]=i; 12 d[i]=2; 13 num[i]=1; 14 mu[i]=-1; 15 } 16 for(int j=1;j<=cnt&&i*pri[j]<maxn;j++){ 17 v[i*pri[j]]=1; 18 if(i%pri[j]==0){ 19 num[i*pri[j]]=num[i]+1; 20 d[i*pri[j]]=d[i]/num[i*pri[j]]*(num[i*pri[j]]+1); 21 break; 22 } 23 num[i*pri[j]]=1; 24 d[i*pri[j]]=d[i]*2; 25 mu[i*pri[j]]=-mu[i]; 26 } 27 } 28 for(int i=1;i<maxn;i++){ 29 d[i]=d[i-1]+d[i]; 30 mu[i]=mu[i-1]+mu[i]; 31 } 32 } 33 signed main(){ 34 work(); 35 scanf("%lld",&t); 36 while(t--){ 37 ans=0; 38 scanf("%lld%lld",&n,&m); 39 if(n>m) swap(n,m); 40 for(int l=1,r;l<=n;l=r+1){ 41 r=min(n/(n/l),m/(m/l)); 42 ans+=d[n/l]*d[m/l]*(mu[r]-mu[l-1]); 43 } 44 printf("%lld\n",ans); 45 } 46 return 0; 47 }
T4:嘤嘤嘤
Problem:
八重樱拥有全村最好的嘤嘤刀。在绯玉丸力量的影响下,八重村成了一条长度为 n 的八重街,并且绯玉丸可以带着八重樱出现在街上的任意地点。而我们的八重樱则会在街上任意穿梭来获得某一地点上的嘤嘤嘤能量,用以升级她的嘤嘤刀。
在每个时刻,都会发生以下 3 个事件:
- 1 x val 表示在 x 地点出现了携带 val 点嘤嘤嘤能量的绯狱丸,并且绯狱丸会吞噬该点的嘤嘤嘤能量,自身原来携带的能量也就是该点的嘤嘤嘤能量变为 val-ai 点,ai 为出现绯狱丸的前一刻,该点存在的嘤嘤嘤能量。
- 2 l r 表示绯玉丸会带着八重樱出现在 [l,r] 间的任意一点。八重樱为了尽快升级她的嘤嘤刀,会获取该区间上最大的嘤嘤嘤能量。特殊的,为了保卫八重村,当 [l,r] 之间存在绯狱丸时,八重樱会优先使用她的嘤嘤刀对付绯狱丸,并获得绯狱丸此时拥有的 ai 点嘤嘤嘤能量。
- 3 l r val 表示绯玉丸会嘤嘤嘤,使得 [l,r] 上的每一个地点的嘤嘤嘤能量增加 val 点(包括绯狱丸)
由于数据纯随机,可能会出现绯狱丸吞绯狱丸的猎奇现象。
Solution:
for 循环暴力模拟即可
Code:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,num,l,r,val,now,x,a[100005],ans; 4 bool b[100005]; 5 int main(){ 6 scanf("%d%d",&n,&m); 7 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 8 while(m--){ 9 scanf("%d",&num); 10 if(num==1){ 11 scanf("%d%d",&x,&val); 12 a[x]=val-a[x]; 13 b[x]=1; 14 } 15 if(num==2){ 16 scanf("%d%d",&l,&r); 17 val=0; 18 for(int i=r;i>=l;i--){ 19 if(b[i]){ 20 now=i; 21 b[i]=0; 22 val=a[i]; 23 break; 24 } 25 if(val<a[i]){ 26 now=i; 27 val=a[i]; 28 } 29 } 30 a[now]=0; 31 ans+=val; 32 printf("%d\n",val); 33 } 34 if(num==3){ 35 scanf("%d%d%d",&l,&r,&val); 36 for(int i=l;i<=r;i++) a[i]+=val; 37 } 38 } 39 if(ans<10000) cout<<"QAQ"; 40 else if(ans>=10000&&ans<10000000) cout<<"Sakura"; 41 else cout<<"ice"; 42 return 0; 43 }