1018 求n!的位数
#include <iostream>
#include<cmath>
using namespace std;
typedef long long ll;
#define sd(a) scanf("%d",&a);
int main()
{
int n,t;
sd(t);
while(t--)
{
sd(n);
double s=0;
for(int i=1;i<=n;i++)
s+=log10(i);
printf("%d\n",(int)s+1);
}
return 0;
}
1233最小生成树
模板题
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MAX 100
#define MAXCOST 0x7fffffff
const int maxn=10005;
int graph[MAX][MAX];
int prim(int graph[][MAX], int n)
{
int lowcost[MAX];//表示以i为终点的边的最小权值
int mst[MAX];//表示 low[i]对应边 对应的起点
int min, minid, sum = 0;
//从顶点一初始化
for (int i = 2; i <= n; i++)
{
lowcost[i] = graph[1][i];
mst[i] = 1;
}
mst[1] = 0;//表示i已经进树
for (int i = 2; i <= n; i++)
{
min = MAXCOST;
minid = 0;
for (int j = 2; j <= n; j++)
{
if (lowcost[j] < min && lowcost[j] != 0)
{
min = lowcost[j];
minid = j;
}
}
// cout << "V" << mst[minid] << "-V" << minid << "=" << min << endl;
sum += min;
lowcost[minid] = 0;//表示minid已经进树
//更新
for (int j = 2; j <= n; j++)
{
if (graph[minid][j] < lowcost[j])
{
lowcost[j] = graph[minid][j];
mst[j] = minid;
}
}
}
return sum;
}
int main()
{
int n;
while(cin>>n&&n)
{
//初始化图G
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
graph[i][j] = MAXCOST;
//构建图G
int x,y,v;
for (int k = 1; k <= n*(n-1)/2; k++)
{
cin >> x >> y >> v;
graph[x][y] = v;
graph[y][x] = v;
}
//求解最小生成树
v = prim(graph, n);
//输出最小权值和
cout << v << endl;
}
return 0;
}
1796 容斥原理
题意:给n和m,m个数,在小于n的数中,有多少为m个数的倍数。
思路:m个数的倍数-重复计入的部分,主要是理解容斥原理。
//二进制
#include<cstdio>
#include<iostream>
using namespace std;
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
int arr[25];
int main()
{
int n,m;
while(scanf("%d %d",&n,&m)!=EOF)
{
int num=0;
int ans=0;
for(int i=1;i<=m;i++)
{
int ai;
scanf("%d",&ai);
if(ai!=0)//数据好坑,还可能为0
arr[num++]=ai;
}
//num种情况,对应二进制num位(0~num-1)
for(int i=1;i<(1<<num);i++)
{
int lcm=1,sum=0;
for(int j=0;j<num;j++)
{
if(i&(1<<j))
{
sum++;//位上为一的个数
lcm=lcm/gcd(lcm,arr[j])*arr[j];//最小公倍数
}
}
if(sum%2==0)ans-=(n-1)/lcm;//偶减
else ans+=(n-1)/lcm;//奇加
}
printf("%d\n",ans);
}
return 0;
}
//dfs
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int arr[25];
int n,m,num,ans;
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
void dfs(int a,int lcm,int id)
{
lcm=arr[a]/gcd(lcm,arr[a])*lcm;
if(id%2==0)
ans-=(n-1)/lcm;
else
ans+=(n-1)/lcm;
//深搜,eg:A->AB->ABC,B->BC,C
for(int i=a+1;i<num;i++)
dfs(i,lcm,id+1);
}
int main()
{
while(scanf("%d %d",&n,&m)!=EOF)
{
num=0,ans=0;
for(int i=1;i<=m;i++)
{
int ai;//注意0这种情况
cin>>ai;
if(ai!=0)
arr[num++]=ai;
}
for(int i=0;i<num;i++)
dfs(i,arr[i],1);
cout<<ans<<endl;
}
return 0;
}
2512 贝尔数
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2005;
#define mod 1000
ll s1[maxn][maxn];//第一类
ll s2[maxn][maxn];//第二类
ll s3[maxn];//贝尔数
void stirling1()
{
s1[0][0]=1;
for(int i=1;i<=maxn;i++)
for(int j=1;j<=i;j++)
s1[i][j]=s1[i-1][j-1]+(i-1)*s1[i-1][j];
}
void stirling2()
{
s2[0][0]=1;
for(int i=1;i<=maxn;i++)
for(int j=1;j<=i;j++)
s2[i][j]=(s2[i-1][j-1]+j*s2[i-1][j])%mod;
}
void bell() //求贝尔数
{
for(int i=1;i<maxn;i++)
{
s3[i]=0;
for(int j=0;j<=i;j++)
s3[i]=(s3[i]+s2[i][j])%mod;
}
}
int main()
{
int t;
cin>>t;
stirling2();
bell();
while(t--)
{
int n;
cin>>n;
cout<<s3[n]<<'\n';
}
return 0;
}
4135 容斥原理+分解质因子
题意:给定区间[a,b],n,求在[a,b]中有多少个和n互质的数;
思路:[a,b]总数-与n不互质的数=ans;求出n的质因子,利用容斥原理,求出质因子在[a,b]的倍数个数-重复部分;
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll num;
ll arr[20];
void init(ll n)//分解质因子+二进制化
{
num=0;
for(ll i=2;i*i<=n;i++)
if(n%i==0)
{
while(n%i==0)n/=i;
arr[num++]=i;
}
if(n>1)arr[num++]=n;
}
ll solve(ll n)//
{
ll ans=0;
for(ll i=1;i<(1ll<<num);i++)
{
ll l=1,s=0;
for(ll j=0;j<num;j++)
if(i>>j&1)
{
s++;//该为为1
l*=arr[j];//已是质数,不用gcd
}
if(s&1)ans+=n/l;
else ans-=n/l;
}
return ans;
}
int main()
{
int t;
ll a,b,n;
scanf("%d",&t);
int cas=0;
while(t--)
{
scanf("%lld%lld%lld",&a,&b,&n);
init(n);
printf("Case #%d: %lld\n",++cas,b-a+1-solve(b)+solve(a-1));
}
return 0;
}
6281 公式转化
double精度不够,把式子交叉相乘;
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<iostream>
#include<cstdlib>
using namespace std;
typedef long long ll;
struct yyqxwyb
{
ll a,b,c;
int pos;
};
yyqxwyb zz[1010];
bool cmp(yyqxwyb x,yyqxwyb y)
{
if((x.a+x.b)*y.c!=(y.a+y.b)*x.c)return (x.a+x.b)*y.c<(y.a+y.b)*x.c;
else return x.pos<y.pos;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
memset(zz,0,sizeof(zz));
for(int i=1;i<=n;i++)
{
cin>>zz[i].a>>zz[i].b>>zz[i].c;
zz[i].pos=i;
}
sort(zz+1,zz+n+1,cmp);
for(int i=1;i<=n;i++)
{
if(i==1)cout<<zz[i].pos;
else cout<<" "<<zz[i].pos;
}
cout<<'\n';
}
return 0;
}
6282 思维+位运算
题意:给字符串a,b(只包含小写字母a,b,c);通过增、删“aa”、“bb”、“abab”,能否使字符串a转化成b?
思路:显然只能使a,b两个两个操作;首先c的个数要相等,然后以c为分界,每一块之间a,b个数%2后相同,判断时可以用位运算。
//a^a=0,a^0=a,b^a^a=b
//若a偶b偶,异或后为0;若a偶b奇,异或后为b;若a奇b偶,异或后为a;若a奇b奇,异或后为ab;
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<string.h>
using namespace std;
typedef long long ll;
int ss[2][10010];
string a,b;
int judge(int x,string s)
{
int num=0;
int sum=0;
for(int i=0;i<=s.length();i++)
{
if(s[i]=='c'||i==s.length())
{//i==s.length考虑字符串最后一块eg:acaab,特殊(acac)
ss[x][num++]=sum;
sum=0;
}
sum^=s[i];//这里对应ascii码
}
return num;
}
int main()
{
while(cin>>a>>b)
{
memset(ss,0,sizeof(ss));
int num1=judge(0,a);
int num2=judge(1,b);
//num-2是c个数
if(num1!=num2)
cout<<"No"<<'\n';
else
{
int f=1;
for(int i=0;i<num1;i++)
{
if(ss[0][i]!=ss[1][i])
{
cout<<"No"<<'\n';
f=0;
break;
}
}
if(f==1)cout<<"Yes"<<'\n';
}
}
return 0;
}
6286 容斥原理
题意:给两个区间[a,b] [c,d],求有多少个(x,y)存在(a<=x<=b,c<=y<=d),使xy=k*2018(k是整数);
思路:2018的因子只有1 2 1009 2018;只需判断在[a,b]区间其因子个数乘对应另一因子在[c,d]的个数,再减去重复计算的。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
//在当前[l,r]区间x因子的个数
ll fac(int l,int r,int x)
{
return r/x-(l-1)/x;
}
int main()
{
int l1,r1,l2,r2;
while(~scanf("%d%d%d%d",&l1,&r1,&l2,&r2))
{
ll ans=0;
ans+=(fac(l1,r1,2018)*(r2-l2+1));
ans+=(fac(l2,r2,2018)*(r1-l1+1));
ans-=(fac(l1,r1,2018)*fac(l2,r2,2018));
ans+=((fac(l1,r1,1009)-fac(l1,r1,2018))*(fac(l2,r2,2)-fac(l2,r2,2018)));
ans+=((fac(l2,r2,1009)-fac(l2,r2,2018))*(fac(l1,r1,2)-fac(l1,r1,2018)));
printf("%lld\n",ans);
}
return 0;
}