做了点数论的题

错位排列

这是一道水题,名字就直接告诉了题的内容和做题的方法,那么直接使用公式就可以了

//错排问题
//就是不可以放在自己原来的位置上 
//那么直接根据公式来就可以了
//D=n!*(1-1/1!+1/2!+...) 
#include<bits/stdc++.h>
using namespace std;
long long fact[15];
inline void init(){
	fact[0]=1;
	for(int i=1;i<=12;i++)fact[i]=fact[i-1]*i;
}
int main(){
	#ifndef ONLINE_JUDGE
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
	#endif
	init();
	long long res;
	int n;
	scanf("%d",&n);
	res=fact[n];
	double tmp=1;
	for(int i=1;i<=n;i++){
		tmp+=(pow(-1,i)/(fact[i]+0.0));
	}
	printf("%.0lf\n",res*tmp);
	return 0;
}

计数器

大概就是统计1~n中每一个数字出现了多少次。有10^9的数量级,所以不可以枚举的。因此要采取把每一位的数字分开来进行计算,即分解每一位,然后这一位前面的数字乘以这一位的权值(它在十的第几位,权值就是十的第几次方),如果说这一位数字大于我们统计的数字,那么还可以再加上一次权值,而如果等于,则应该加上它后面的位数组成的数字+1+1是因为后面的组成的还有全0。比如2533,再统计5时,统计到第三位,因为这这一位等于5,后面的位数组成的数字是33,但是漏了2500,所以要+1(注意0要进行特殊的判定,因为0在最前面是不符合计数的规则的)。
那么代码如下
洛谷的链接

//计数器 
#include<bits/stdc++.h>
using namespace std;
int data[11];
void calc(int num,int tot){
	int cnt=0,k=1,upp,low,now;
	int tmp=tot;
	while(k<=tot){
		upp=tot/(k*10);
		low=tot%k;
		now=tmp%10;
		cnt+=(upp*k);
		if(now>num)cnt+=k;
		if(now==num)cnt+=(low+1);
		if(num==0)cnt-=k;
		k*=10;	
		tmp/=10;
		if(tmp<10&&num==0)break;	
	}
	data[num]=cnt;
}
int main(){
	#ifndef ONLINE_JUDGE
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
	#endif
	memset(data,0,sizeof(data));
	int n;
	cin>>n;
	for(int i=0;i<=9;i++){
		calc(i,n);
	}
	
	for(int i=0;i<=9;i++)printf("%d\n",data[i]);
	return 0;
}
posted @ 2019-01-18 18:29  Perisino  阅读(143)  评论(0编辑  收藏  举报