【已整理】【数论】【总】【水】
1.lightoj 1341
题意:给你一个a表示矩形(不能是正方形)的面积,给你一个b表示最小的可能的边长,问你这样的矩形有多少对。我觉得这个要是多来几个极端数据,包括我的程序以及网上的题解都会T。可能这题专门就是为了考察因子个数的计算方法吧。因子个数只要素因数分解一下就求出来。然后题目给的应该都是a比较大,b很小的样例,这样如果暴力枚举b到根号a的数,就会T。所以只能先算因子个数,再暴力枚举b。但是如果只是这样写,也可以专门出数据卡时间(比如b也很大),所以说这题可能专门就是为了考察素因子分解吧。我自己写的程序是根据b的范围讨论了一下,但是也没有太大的卵用,还是可以出数据卡时间。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long int ll; const int MAXN=1000005; int prime[MAXN/10]; bool vis[MAXN]; int tot; void get_prime(){ tot=0; memset(vis,false,sizeof(vis)); for(int i=2;i<MAXN;i++){ if(!vis[i]){ prime[tot++]=i; for(int j=i+i;j<MAXN;j+=i) vis[j]=true; } } } ll decap(ll num){ ll res=1; for(int i=0;i<tot&&prime[i]*prime[i]<=num;i++){ if(num%prime[i]) continue; ll tt=0; while(num%prime[i]==0){ tt++; num/=prime[i]; } res*=(tt+1); } if(num>1) res*=2; return res; } int main(){ get_prime(); int t; ll a,b,c; scanf("%d",&t); for(int cas=1;cas<=t;cas++){ scanf("%lld%lld",&a,&b); ll tt=sqrt(a); if(b>tt){ printf("Case %d: 0\n",cas); continue; } ll res=0; if(b<=10000){ for(ll i=1;i<b&&i<tt;i++){ if(a%i==0) res++; } res=decap(a)/2-res; } else{ for(ll i=b;i<tt;i++){ if(a%i==0) res++; } if(tt*tt<a&&a%tt==0) res++; } printf("Case %d: %lld\n",cas,res); } return 0; }
根据这题得出了一个结论,一个数的因子,两两相乘的等于原数的因子对数等于因子个数/2,这里的除法是向下取整除法。首先,一个数的因子,大于根号n,小于根号n的因子个数一定是一一对应,所以个数是相等的,但是根号n也可能是一个因子,所以一个数的因子数如果是奇数个,则根号n也一定是其中一个因子,所以因子对数是向下取整除以2。
2.lightoj 1213
题意:给了你一段代码。代码的意思是,从n个数里,可重复的选择k个数,res=(res+求和(a【所有选择的k个数】))%mod
在每个位置,每个数都可以被选择,则一共有n^k种,每次选出了k个数,则一共选出了k*n^k,由于每个数被选的概率相等,每个数被选出k*n^(k-1)次。
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace std; typedef long long int ll; const int MAXN=36666; ll mod; ll quick(ll n,ll k){ n%=mod; ll res=1; while(k){ if(k&1) res=(res*n)%mod; n=(n*n)%mod; k>>=1; } return res; } int main(){ int t; ll n,k,a; scanf("%d",&t); for(int cas=1;cas<=t;cas++){ scanf("%lld%lld%lld",&n,&k,&mod); ll tt=quick(n,k-1); tt=(tt*k)%mod; ll res=0; for(int i=0;i<n;i++){ scanf("%lld",&a); res=(res+a*tt)%mod; } printf("Case %d: %lld\n",cas,res); } return 0; }
3.poj2116 Death to Binary?
这题虽然是水题,但是还是有坑点,就是0要单独表示成一个0。还学到了一个东西,用斐波那契数列表示一个数。
F[0]=1,F[1]=2,F[n]=F[n-1]+F[n-2]。
第i位的权值为F[i]
这题告诉我们一个结论,所有的数都可以用斐波那契进制表示出来。且某些数的表示方法不止一种,但是没有连续相邻两个1的表示方法是唯一的。
我观察了一下,发现一个规律,给你一个十进制数n,让你表示成一个斐波那契进制的数,则一定是找到最接近n的斐波那契数,这一位为1,这一位同时也是最高位,n-=这个斐波那契数。递归下去,直到n变为0,整个斐波那契数就构造出来了,且这个斐波那契数满足没有相邻的1的条件。
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace std; typedef long long int ll; const int MAXN=87; char a[MAXN],b[MAXN],c[MAXN]; ll f[MAXN]; void init(){ f[0]=1;f[1]=2; for(int i=2;i<MAXN;i++){ f[i]=f[i-1]+f[i-2]; } } int solve(char *a,ll num){ for(int i=0;i<MAXN;i++) a[i]='0'; int cnt=-1; while(num){ int loc=upper_bound(f,f+MAXN,num)-f-1; num-=f[loc]; if(cnt==-1) cnt=loc; a[loc]='1'; } return cnt; } void print(char *s,int len){ for(int i=len-1;i>=0;i--) printf("%c",s[i]); printf("\n"); } void fun(){ int res=0; for(int i=0;i<40;i++) res+=f[i]; printf("%d\n",res); } int main(){ int t; init(); while(~scanf("%s%s",a,b)){ int lena=strlen(a); int lenb=strlen(b); int lenc; ll aa=0,bb=0,cc; for(int i=0;i<lena;i++){ if(a[i]=='1') aa+=f[lena-i-1]; } for(int i=0;i<lenb;i++){ if(b[i]=='1') bb+=f[lenb-i-1]; } cc=aa+bb; lena=solve(a,aa)+1; lenb=solve(b,bb)+1; lenc=solve(c,cc)+1; if(lena==0) lena++; if(lenb==0) lenb++; if(lenc==0) lenc++; for(int i=0;i<lenc+2-lena;i++) printf(" "); if(aa>0) print(a,lena); else printf("0\n"); printf("+"); for(int i=1;i<lenc+2-lenb;i++) printf(" "); if(bb>0) print(b,lenb); else printf("0\n"); printf(" "); for(int i=0;i<lenc;i++) printf("-"); printf("\n"); printf(" "); if(cc>0) print(c,lenc); else printf("0\n"); printf("\n"); } return 0; }
3.poj2429 GCD & LCM Inverse
题意:给你最大公因数和最小公倍数,让你求原来的两个数,如果有多解,输出两个数的和最小的情况。
首先两个数肯定都至少有最大公因数那么大,然后就是最小公倍数/最大公因数的这个数的分配问题
举个例子,30和10800,素因数分解后分别为2*3*5和2*2*2*2*3*3*3*5*5。那么两者至少都有2*3*5。然后需要分配2*2*2*3*3*5。我们不能将同一个素因数拆开来分给两者,所以分配的实际上是8*9*5。那么原题就转化为了给定矩形的面积,求最小周长,爆搜一下即可。
#include<cstdio> #include<cstring> #include<algorithm> #include<ctime> #include<set> #include<cmath> using namespace std; typedef long long int ll; const int MAXN=1000005; ll factor[MAXN]; int tot; const int S=5; ll muti_mod(ll a,ll b,ll c){ //返回(a*b) mod c,a,b,c<2^63 a%=c; b%=c; ll ret=0; while (b){ if (b&1){ ret+=a; if (ret>=c) ret-=c; } a<<=1; if (a>=c) a-=c; b>>=1; } return ret; } ll pow_mod(ll x,ll n,ll mod){ //返回x^n mod c ,非递归版 if (n==1) return x%mod; int bit[90],k=0; while (n){ bit[k++]=n&1; n>>=1; } ll ret=1; for (k=k-1;k>=0;k--){ ret=muti_mod(ret,ret,mod); if (bit[k]==1) ret=muti_mod(ret,x,mod); } return ret; } bool check(ll a,ll n,ll x,ll t){ //以a为基,n-1=x*2^t,检验n是不是合数 ll ret=pow_mod(a,x,n),last=ret; for (int i=1;i<=t;i++){ ret=muti_mod(ret,ret,n); if (ret==1 && last!=1 && last!=n-1) return 1; last=ret; } if (ret!=1) return 1; return 0; } bool Miller_Rabin(ll n){ if(n==1) return false; ll x=n-1,t=0; while ((x&1)==0) x>>=1,t++; bool flag=true; if (t>=1 && (x&1)==1){ for (int k=0;k<S;k++){ ll a=rand()%(n-1)+1; if (check(a,n,x,t)) {flag=true;break;} flag=0; } } if (!flag || n==2) return true; return false; } ll gcd(ll a,ll b){ if (a==0) return 1; if (a<0) return gcd(-a,b); while (b){ ll t=a%b; a=b; b=t; } return a; } ll Pollard_rho(ll x,ll c){ ll i=1,x0=rand()%x,y=x0,k=2; while (1){ i++; x0=(muti_mod(x0,x0,x)+c)%x; ll d=gcd(y-x0,x); if (d!=1 && d!=x){ return d; } if (y==x0) return x; if (i==k){ y=x0; k+=k; } } } void findfac(ll n){ //递归进行质因数分解N if (Miller_Rabin(n)){ factor[tot++] = n; return; } ll p=n; while (p>=n) p=Pollard_rho(p,rand() % (n-1) +1); findfac(p); findfac(n/p); } ll res=1; ll bound; ll number; void dfs(int u,ll num){ if(u>=tot){ if(bound==-1||number/num+num<bound){ bound=number/num+num; res=num; } return; } dfs(u+1,num); dfs(u+1,num*factor[u]); } int main(){ ll n,m; while(~scanf("%lld%lld",&n,&m)){ if(n==m){ printf("%lld %lld\n",n,m); continue; } ll tt=m/n; tot=0; findfac(tt); sort(factor,factor+tot); int j=0; ll pre=factor[0]; for(int i=1;i<tot;i++){ if(factor[i]!=pre){ factor[++j]=factor[i]; pre=factor[j]; } else factor[j]*=pre; } tot=j+1; number=tt; bound=-1; dfs(0,1); ll low=n*res,high=n*(number/res); if(low>high) swap(low,high); printf("%lld %lld\n",low,high); } return 0; }

浙公网安备 33010602011771号