问题 A: 阶乘分解
题目描述
给定整数N(1≤N≤10^6),试把阶乘N!分解质因数,按照算术基本定理的形式输出分解结果中的pi和ci即可。
输入
一个整数N。
输出
N! 分解质因数后的结果,共若干行,每行一对pi, ci,表示含有pi^ci项。按照pi从小到大的顺序输出。
样例输入
5
样例输出
2 3 3 1 5 1
打一个素数表(顺便把每个数的素因子push_back进vector),然后暴力2--n,放到vis数组里,最后扫一遍素数表输出
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+7;
int n,prim[maxn],cnt;
int vis[maxn];
vector<int> vec[maxn];
void init(){
for(int i=2;i<maxn;i++)
if(!vis[i]){
prim[cnt++] = i;
for(int j=i;j<maxn;j+=i)
vis[j] = 1,vec[j].push_back(i);
}
memset(vis,0,sizeof(vis));
}
int main() {
init();
scanf("%d",&n);
if(n==1)
return 0*printf("2 0\n");
for(int i=2;i<=n;i++){
int ti = i;
for(auto j:vec[i]){
while(ti%j==0)
vis[j]++,ti/=j;
}
}
for(int i=0;i<cnt;i++)
if(vis[prim[i]])
printf("%d %d\n",prim[i],vis[prim[i]]);
return 0;
}
反素数ant
问题 E: 余数之和
题目描述
给出正整数n和k,计算j(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值
其中k mod i表示k除以i的余数。
例如j(5, 3)=3 mod 1 + 3 mod 2 + 3 mod 3 + 3 mod 4 + 3 mod 5=0+1+0+3+3=7输入
输入仅一行,包含两个整数n, k。
1<=n ,k<=10^9输出
输出仅一行,即j(n, k)。
样例输入
5 3
样例输出
7
容易看出
那么不好求的就是这个,
先看个简单的,怎么求,解法肯定不能暴力(会超时),
那么设(l,r为区间左右端点)
那么
很明显这样就可以了
for(ll l=1,r;l<=k;l=r+1){
r = k/(k/l);
ans += (r-l+1)*(k/l);
}
现在回过头来看,发现其实就是加了个权值,那么只要
for(ll l=1,r;l<=k;l=r+1){
r = k/(k/l);
ans += (r+l)(r-l+1)/2*(k/l);
}
但是这样会wa,因为并不一定会将整个区间加进去,所以
这是Ac代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k;
ll Get(ll n,ll k){
ll ans = 0;
ll cnt = min(k,n);
for(ll l=1,r;l<=cnt;l=r+1){
r = min(cnt,k/(k/l));
ans += (r+l)*(r-l+1)/2*(k/l);
}
return n*k-ans;
}
int main() {
cin>>n>>k;
cout<<Get(n,k)<<endl;
return 0;
}
G: 同余方程
求关于 x 的同余方程 ax ≡ 1 (mod b)的最小正整数解。
输入只有一行,包含两个正整数 a, b,用一个空格隔开。
输出只有一行,包含一个正整数 x0,即最小正整数解。输入数据保证一定有解。
exgcd
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll exgcd(ll a,ll b,ll& x,ll& y){
if(b == 0){
x = 1,y = 0;
return a;
}
ll ans = exgcd(b, a%b, y, x);
y -= x*(a/b);
return ans;
}
int main(){
ll a,b,x,y;
scanf("%lld%lld",&a,&b);
exgcd(a,b,x,y);
printf("%lld\n",(x+b)%b);
return 0;
}
问题 I: Fibonacci
In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn − 1 + Fn − 2 for n ≥ 2. For example, the first ten terms of the Fibonacci sequence are:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …
An alternative formula for the Fibonacci sequence is
Given an integer n, your goal is to compute the last 4 digits of Fn.
The input test file will contain multiple test cases. Each test case consists of a single line containing n (where 0 ≤ n ≤ 1,000,000,000). The end-of-file is denoted by a single line containing the number −1.
For each test case, print the last four digits of Fn. If the last four digits of Fn are all zeros, print ‘0’; otherwise, omit any leading zeros (i.e., print Fn mod 10000).
矩阵快速幂=-=
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
int a[2][2];
void zero(){
a[1][1]=a[0][0]=a[0][1]=a[1][0]=0;
}
void one(){
a[0][1]=a[1][0]=0;
a[0][0]=a[1][1]=1;
}
void Fib(){
a[1][1]=0;
a[0][0]=a[0][1]=a[1][0]=1;
}
};
node operator * (node a,node b){
node c;
c.zero();
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
for(int k=0;k<2;k++)
c.a[i][j] = (c.a[i][j]+a.a[i][k]*b.a[k][j]%10000)%10000;
}
}
return c;
}
node Pow(node A,int b){
node Ans;
Ans.one();
while(b){
if(b&1)
Ans = Ans*A;
A = A*A;
b>>=1;
}
return Ans;
}
int main(){
node P;
P.Fib();
int t;
while(cin>>t && ~t){
node Ans = Pow(P,t);
cout<<Ans.a[0][1]<<endl;
}
return 0;
}
问题 K: 球形空间产生器
有一个球形空间产生器能够在n维空间中产生一个坚硬的球体。现在,你被困在了这个n维球体中,你只知道球面上n+1个点的坐标,你需要以最快的速度确定这个n维球体的球心坐标,以便于摧毁这个球形空间产生器。
第一行是一个整数n(1<=N=10)。接下来的n+1行,每行有n个实数,表示球面上一点的n维坐标。每一个实数精确到小数点后6位,且其绝对值都不超过20000。
有且只有一行,依次给出球心的n维坐标(n个实数),两个实数之间用一个空格隔开。每个实数精确到小数点后3位。数据保证有解。你的答案必须和标准输出一模一样才能够得分。
给出两个定义:
1 球心:到球面上任意一点距离都相等的点。
2 距离:设两个n为空间上的点A, B的坐标为(a1, a2, …, an), (b1, b2, …, bn),则AB的距离定义为:dist = sqrt( (a1-b1)^2 + (a2-b2)^2 + … + (an-bn)^2 )
高斯消元,算是个板子吧,
假设圆心点为
那么对于圆上两个点()和()来说
显然有
消掉再展开得到
也就是一个方程组,然后高斯消元即可
#include <bits/stdc++.h>
using namespace std;
const int maxn = 20;
double a[maxn][maxn],point[maxn][maxn];
double o2(double x){return x*x;}
void gauss(int n,int m){
for(int i=1;i<=n;i++){
int ml = i;
for(int j=i+1;j<=n;j++)///find the max in the a[i---n][i]
if (abs(a[j][i])>abs(a[ml][i]))
ml = j;
if (ml!=i)///swap the a[min_line] and a[i]
for(int j=1;j<=m;j++)
swap(a[ml][j],a[i][j]);
double t = a[i][i];
for(int j=1;j<=m;j++)///unitized the a[i]
a[i][j] /= t;
for(int j=1;j<=n;j++)/// change the a[1---n] ( subtract the t*a[i] )
if (j!=i&&a[j][i]!=0){
double t = a[j][i];
for(int k=1;k<=m;k++)/// subtract the t*a[i]
a[j][k] -= t*a[i][k];
}
}
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n+1;i++)
for(int j=1;j<=n;j++)
scanf("%lf",&point[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j] = 2*(point[i][j]-point[i+1][j]),a[i][n+1] += o2(point[i][j])-o2(point[i+1][j]);
gauss(n,n+1);
for(int i=1;i<=n-1;i++)
printf("%.3f ",a[i][n+1]);
printf("%.3f\n",a[n][n+1]);
return 0;
}
问题 M: 计算系数
给定一个多项式(by+ax)k,请求出多项式展开后xn * ym 项的系数。
共一行,包含5 个整数,分别为 a ,b ,k ,n ,m,每两个整数之间用一个空格隔开。0≤k≤1000, 0≤n,m≤k 且 n+m=k, 0≤a,b≤100,000
输出共1 行,包含一个整数,表示所求的系数,这个系数可能很大,输出对10007 取模后的结果。
排列组合+逆元
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int p = 10007,maxn = 1e3+7;
ll Fu[maxn],inv[maxn];
ll Pow(ll a,ll b){
a %= p;
ll ans = 1;
while(b){
if(b&1)
ans = ans*a%p;
a = a*a%p;
b>>=1;
}
return ans;
}
void init(){
Fu[0] = 1;
for(int i=1;i<maxn;i++)
Fu[i] = Fu[i-1]*i%p;
inv[maxn-1] = Pow(Fu[maxn-1],p-2);
for(int i=maxn-2;~i;i--)
inv[i] = inv[i+1]*(i+1)%p;
}
ll C(ll n,ll m){
return Fu[n]*inv[m]%p*inv[n-m]%p;
}
int main(){
init();
ll a,b,k,n,m;///(b*y+a*x)^k
cin>>a>>b>>k>>n>>m;
/// C(k,m)*b^m* a^k-m * y^m*x^k-m
cout<<(C(k,m)*Pow(b,m)%p*Pow(a,n)%p)<<endl;
return 0;
}