備戰noip week1
阿新 • • 發佈:2020-09-03
Pairs of integers
題意:給出一個整數N(N<=1e9)求兩個整數X,Y使得X+Y=N,求所有的解
其中Y是X直接去掉一位後得到的(1034->134,100->00.etc)
題解:對於整數X,我們列舉它的每一位(第i位),並且列舉這一位上所有可能的數字d
令第i位前的數字構成的數為x,第i位後的數字構成的數為y
那麼就有\(x*10^i+d*10^{i-1}+y+x*10^{i-1}+y=N\)
因此\(11*10^{i-1}+2y=N-d*10^{i-1}\)
解不定方程即可,然後搞出所有解就行了
用map實現本題十分方便(既可以去重也可以排序)
P.S. 本題的輸出十分有意思
code:
#include<cstdio> #include<map> using namespace std; typedef long long ll; ll N,P10[15]; map<ll,ll>ans; void exgcd(ll a,ll b,ll &g,ll &x,ll &y) { if(!b){x=1;y=0;g=a;return;} exgcd(b,a%b,g,x,y); ll xx=x; x=y;y=xx-a/b*y; } inline int ws(ll x) { if(!x)return 1; int anss=0; for(;P10[anss]<=x;++anss); return anss; } int main() { P10[0]=1; for(int i=1;i<=10;++i)P10[i]=P10[i-1]*10ll; while(scanf("%lld",&N)!=EOF) { ans.clear(); int len=ws(N); if(N%P10[len-1]==0)ans[N]=0; for(int i=1;i<=len;++i) { ll a=11*P10[i-1],b=2,g=0,x=0,y=0; exgcd(a,b,g,x,y); ll xx=x,yy=y; for(int d=0;d<10;++d) { x=xx,y=yy; ll c=N-1ll*d*P10[i-1]; if(c%g)continue; ll s=c/g,_a=0,_b=0; x*=s,y*=s;_a=a/g,_b=b/g; y=(y%_a+_a)%_a; for(;y<P10[i-1];y+=_a) { x=(c-y*b)/a; ll X=x*P10[i]+d*P10[i-1]+y,Y=x*P10[i-1]+y; if(X!=Y&&X>=0&&Y>=0)ans[X]=Y; } } } printf("%lld\n",ans.size()); for(map<ll,ll>::iterator it=ans.begin();it!=ans.end();it++) printf("%lld + %0*lld = %lld\n",it->first,ws(it->first)-1,it->second,N); } return 0; }
最小公倍數的最小和
注意細節:
1.n=1
2.n為素數
3.n=2^31-1(答案會越界)
#include<bits/stdc++.h> using namespace std; int n,kase; int main() { while(scanf("%d",&n)==1&&n) { long long ans=0;int nn=n,mx=(int)sqrt(n); for(int i=2;i<=mx;++i) { int cnt=1; while(n%i==0)n/=i,cnt*=i; if(cnt!=1)ans+=1ll*cnt; if(n==1)break; } if(ans==0)ans=1ll*nn+1; else if(n!=1)ans+=1ll*n; if(ans==1ll*nn)++ans; if(nn==1)ans=2; printf("Case %d: %lld\n",++kase,ans); } return 0; }
選擇與除法
質因數分解。統計指數就可以了
#include<bits/stdc++.h>
using namespace std;
const int N=10005;
int pr[N],p,q,r,s;
double ans;
inline int cp(int &x,int d)
{
int cnt=0;
while(x%d==0)x/=d,++cnt;
return cnt;
}
inline void work(int x,int d)
{
int mx=(int)sqrt(x+1);
for(int i=2;i<=mx&&x!=1;++i)
if(x%i==0)pr[i]+=d*cp(x,i);
if(x>1)pr[x]+=d;
}
inline void ad(int x,int d)
{
for(int i=2;i<=x;++i)
work(i,d);
}
inline void solve()
{
ans=1;
for(int i=2;i<=N-5;++i)
ans*=pow(i,pr[i]),pr[i]=0;
printf("%.5lf\n",ans);
}
int main()
{
while(scanf("%d%d%d%d",&p,&q,&r,&s)==4)
{
ad(p,1);ad(q,-1);
ad(s,1);ad(r,-1);
ad(r-s,1);ad(p-q,-1);
solve();
}
return 0;
}
交表
題意:求出整數對個數(x,y)(x,y<=n n<=5e4)使得其最大公約數為1
題解:這樣的整數對除(1,1)其他的x不等於y
不妨設x>y(x<y同理)那麼只要確定x,答案就是phi(x)
篩出所有phi(x),求出字首和即可
code:
#include<bits/stdc++.h>
using namespace std;
const int N=50005;
vector<int>pr;
int phi[N],sm[N],n;
bool flag[N];
inline void pre()
{
int m=N-5;
for(int i=2;i<=m;++i)
{
if(!flag[i]){phi[i]=i-1;pr.push_back(i);}
for(int j=0;j<pr.size();++j)
{
if(i*pr[j]>m)break;
flag[i*pr[j]]=true;
if(i%pr[j])phi[i*pr[j]]=phi[i]*phi[pr[j]];
else{phi[i*pr[j]]=phi[i]*pr[j];break;}
}
}
for(int i=2;i<=m;++i)
sm[i]=sm[i-1]+phi[i];
}
int main()
{
pre();
while(scanf("%d",&n)==1&&n)
printf("%d\n",sm[n]*2+1);
return 0;
}
樹林裡的樹
題解:
可以發現座標軸上有且僅有4個點可以看到,單獨考慮
發現只用考慮右上角的點就行了(其他方位同理)
由於列數較少行數較多,因此列舉列數
對於列x,能看到的當且僅當其縱座標與x互質
不難想到尤拉函式
稍稍擴充套件可以證明\(kx+1-(k+1)x\)(其中k為正整數)中與x互質的數的個數仍然為phi(x)
簡略證明:
若d(d<x)與x互質,那麼d+x仍然與x互質
若e(e<=x)與x不互質,那麼e+x仍然與x不互質
由此可以快速計算每列可以看到多少樹
至於餘數部分,暴力計算統計即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2005;
vector<int>p;
int lp[N],phi[N],a,b;
bool flag[N];
int gcd(int x,int y){return y==0?x:gcd(y,x%y);}
inline void pre()
{
int m=N-5;phi[1]=1;
for(int i=2;i<=m;++i)
{
if(!flag[i]){phi[i]=i-1;p.push_back(i);}
for(int j=0;j<p.size();++j)
{
if(i*p[j]>m)break;
flag[i*p[j]]=true;
if(i%p[j])phi[i*p[j]]=phi[i]*phi[p[j]];
else{phi[i*p[j]]=phi[i]*p[j];break;}
}
}
}
int main()
{
pre();
while(scanf("%d%d",&a,&b)==2&&a&&b)
{
ll ans=0,t=0;
for(int i=1;i<=a;++i)
{
int d=b/i;
ans+=1ll*d*phi[i];
for(int j=d*i+1;j<=b;++j)
if(gcd(j,i)==1)++ans;
}
ans*=4;ans+=4;t=1ll*(a*2+1)*(b*2+1)-1;
printf("%.10lf\n",(double)ans/t);
}
return 0;
}