Bi-shoe and phi-shoe 知识点:欧拉函数打表
题意:竹子的得分为它长度的欧拉函数值,Bi-shoe想买竹子给同学,每个同学收到的竹子得分>=他的幸运数字,竹子每单位长度需要花1Xukha。问Bi-shoe最少花多少钱?
思路:欧拉值打表,遍历
#include
#include
#include
using namespace std;
const int N=1e4+10;
const int M=1e6+10;
int euler[M];
int a[N];
void gete()
{
for(int i=1;i<=M;++i)
euler[i]=i;
for(int i=2;i<=M;++i)
{
if(euler[i]==i) //说明是素数
for(int j=i;j<=M;j+=i) //素数的倍数的euler[j]一并改掉
euler[j]=euler[j]/i*(i-1); //euler[j]=euler[j]*(1-1/i)
}
/*for(int i=2;i<=10;++i)
cout<>T;
for(int k=1;k<=T;k++)
{
int n;
cin>>n;
long long ans=0;
for(int i=1;i<=n;++i)
cin>>a[i];
sort(a+1,a+1+n);
for(int i=1,j=2;i<=n&&j<=M;j++)
{
if(euler[j]>=a[i])
{
ans+=j;
i++;
j--;
}
}
cout<<"Case "<
Sigma Function 知识点:规律
记得当时看了很多推导,后悔当时没有写博客的习惯。
题意:1~n中有多少个数,其因子和为偶数
规律:因子和为奇数的有:平方数以及平方数的二倍。总数减去为奇数的就是偶数的
智商不够就暴力打表找规律叭_(:з」∠)_
#include
#include
#include
using namespace std;
typedef long long LL;
int main()
{
int T;
cin>>T;
for(int i=1;i<=T;++i)
{
LL n;
cin>>n;
LL ans=(LL)sqrt(n)+(LL)sqrt(n/2); //中间不强制转换的话会wa
printf("Case %d: %lld\n",i,n-ans);
}
return 0;
}
Leading and Trailing 知识点:快速模指数算法 指数问题转成对数求解
题意:求n^k的前三位和后三位
思路:后三位很好求,只要模1000就能求出,关键是前三位
前三位的求法是这样的,将用科学计数法表示,那么 前三位即取整
我们将a用表示,由于科学计数法中a<10,所以一定是小数,即
//A
#include
#include
#include
using namespace std;
typedef long long ll;
const int mod=1000;
ll quick_mod(ll a,ll k)
{
if(k==0) return 1;
ll ans=1;
while(k)
{
if(k&1)
ans=ans*a%mod;
a=a*a%mod;
k=k>>1;
}
return ans;
}
int main()
{
int T;
cin>>T;
for(int kase=1;kase<=T;kase++)
{
ll n,k;
cin>>n>>k;
ll trail=quick_mod(n,k); //只要模1000就能算出最后三位
double x=k*log10(n)-(int)(k*log10(n)); //强制转换要加括号
double tmp=pow(10,x);
int lead=(int)(tmp*100);
printf("Case %d: %d %03d\n",kase,lead,trail);
}
return 0;
}
Goldbach`s Conjecture 知识点:素数打表
题意:给一个数n,问能找到多少素数对,其和是n
#include
#include
#include
using namespace std;
const int N=1e7+10;
bool tag[N];
int prime[1000000];
int cnt=0;
void getprime()
{
memset(tag,false,sizeof(tag));
tag[0]=tag[1]=1;
for(int i=2;i<=N;++i)
{
if(!tag[i])
prime[++cnt]=i;
for(int j=1;j<=cnt&&prime[j]*i<=N;++j)
{
tag[prime[j]*i]=true;
if(i%prime[j]==0)
break;
}
}
}
int main()
{
getprime();
int T;
cin>>T;
for(int k=1;k<=T;++k)
{
int n;
cin>>n;
int ans=0;
//cout<<"keke"<
G - Harmonic Number (II) 找规律
用正确方法求h(n)
#include
#include
using namespace std;
typedef long long LL;
LL h(LL n)
{
LL res=0;
LL i=1;
for(;i*(i+1)>T;
for(int kase=1;kase<=T;kase++)
{
LL n;
cin>>n;
cout<<"Case "<
I - Harmonic Number
题意:求1 + 1/2 + 1/3 + 1/4 + 1/ 5 +...+ 1/ n
思路:有公式,记不住咋办?将数分组存储的思路
#include
#include
using namespace std;
const int N=1e8+10;
const int NN=1e8/40+10;
//每隔四十记录一次答案 不然空间不够,这个样子的话循环一次 1s 之后每个数进来最多循环39次
double a[NN];
void pre()
{
double sum=0;
for(int i=1;i<1e8+10;++i)
{
sum+=(1.0)/i;
if(i%40==0) a[i/40]=sum;
}
}
int main()
{
//cout<>T;
int cas=0;
while(T--)
{
++cas;
int n;
cin>>n;
int x=n/40; //将数锁定在一个范围,机智
double ans=a[x];
for(int i=x*40+1;i<=n;++i)
ans+=1.0/i;
printf("Case %d: %.10f\n",cas,ans);
}
return 0;
}
J - Mysterious Bacteria
题意: 给出,求最大的
这个y的最大值就是答案
显然的时候最大
这题的坑点在于x可能是负的,我们在处理的时候把它转成正数去做的,如果y是偶数就会导致最终解为正数,所以要把一直除二,除到奇数为止
#include
#include
#include
using namespace std;
typedef long long LL;
const int N=1e6+100;
bool tag[N];
int prime[N];
int cnt;
void getprime()
{
memset(tag,0,sizeof(tag));
tag[0]=tag[1]=1;
for(int i=2;i>1;
}
}
return ans;
}
int main()
{
getprime();
int T;
cin>>T;
for(int kase=1;kase<=T;++kase)
{
LL x; //不用LL的话会爆int有符号最大(2^16)
cin>>x;
cout<<"Case "<
K - Large Division
题意:b是32位有符号整数,判读a是否能整除b
数论的魅力在于:本来以为这道题必须要用大数来做了,but!
如果a<0,先把a转化为绝对值
#include
#include
using namespace std;
typedef long long LL;
int main()
{
int T;
cin>>T;
for(int kase=1;kase<=T;++kase)
{
string a;
LL b,ans=0;
cin>>a>>b;
if(b<0) b=-b;
int len=a.size();
int i=0;
if(a[0]!='-')
{
ans=a[0]-'0';
i=1;
}
else
{
ans=a[1]-'0';
i=2;
}
for(;i
M - Help Hanzo
题意:[a,b]区间内有多少素数 32位数10000以内区间长度判断素数个数
思路:数量太大无法打表,策略是把[a,b]区间->[0,b-a]区间,用素数筛在这个区间范围内筛素数
#include
#include
#include
using namespace std;
const int N=1e6+10;
const int M=2e6;
typedef long long LL;
int tag[N];
LL prime[M];
int interval[100010];
int cnt;
LL a,b;
void getp()
{
memset(tag,0,sizeof(tag));
tag[0]=tag[1]=1;
for(int i=2;ib) break; //用所有平方值小于b的prime去更新那个区间
LL s=(a+prime[j]-1)/prime[j]; //计算第一个比a大的prime[j]的倍数是几倍 (向上取整的好操作)
if(s<2) s=2; //避免把这个素数当成合数筛掉
s*=prime[j];
for(;s<=b;s+=prime[j])
interval[s-a]=1; //把集合整到[0,b-a]
}
int ans=0;
for(int i=a;i<=b;++i)
{
if(!interval[i-a])
++ans;
}
return ans;
}
int main()
{
getp();
int T;
cin>>T;
int kase=0;
while(T--)
{
++kase;
cin>>a>>b;
int ans=solve(a,b);
if(a==1) --ans; //a=1的话在interval里面没有被筛掉
printf("Case %d: %d\n",kase,ans);
}
return 0;
}
N - Trailing Zeroes (III)
题意:给出q,找出n,使得n!的十进制表达最后有q个0
题目的思路很简单,首先n!里面2和5搭配形成10,5的数目比2多,所以有几个5就能有几个10
我记得我是想暴力求出所有情况(打表),但是忽略了q是1e8的量级,这种涉及很大很大的数要用二分法啊
#include
#include
O - GCD - Extreme (II)
题意:求出1~n之间所有数对的最大公约数之和
脑子抽了才会想去暴力。。。
设
则
得到这个递推式后,问题转化为如何求,当然是暴力遍历啦
设表示满足的个数,则
又,所以与n的最大公约数是i的数有个,因此呼啦!最终就变成求欧拉函数了
这道题以及以往做过的数论题提醒我,筛法的思想很重要,特征是一个数由其所有约数更新,用筛法最省时(这种好像叫填表法)
#include
#include
#include
using namespace std;
const int N=4e6+10;
typedef long long LL;
int euler[N];
LL F[N];
LL G[N];
void geteu()
{
for(int i=1;i