2018.10.18 练习赛 数学专练

T1 打气球

题解:

期望递推,不关心具体位置,所以\(F[i][j]\)表示还有\(i\),\(j\)行,列未完;

\(code\):

#include<cstdio> 
#include<algorithm> 
#include<ctype.h>  
#include<vector> 
#include<queue> 
#include<cstring> 
#define lowbit(x) (x&-x) 
#define ll long long 
#define ld double 
#include<map> 
#include<stdlib.h> 
#include<ctime> 
#define mod 19260817 
using namespace std; 

char buf[1<<20],*p1,*p2; 
inline char gc() 
{ 
//    return getchar(); 
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++; 
} 

template<typename T> 
inline void read(T &x) 
{ 
    char tt; 
    bool flag=0; 
    while(!isdigit(tt=gc())&&tt!='-'); 
    tt=='-'?(flag=1,x=0):(x=tt-'0'); 
    while(isdigit(tt=gc())) x=x*10+tt-'0'; 
    if(flag) x=-x; 
} 

int n,m;
int hang,lie;
ld f[2005][2005];
bool heng[2005],zong[2005];

ld dfs(int x,int y)
{
	if(f[x][y]!=-1) return f[x][y];
	if(!x&&!y) return f[x][y]=0.0;f[x][y]=0.0;
	f[x][y]+=(x)?(dfs(x-1,y)*1.0*x*(n-y)):0.0;
//	printf("%.2lf\n",f[x][y]);
	f[x][y]+=(y)?(dfs(x,y-1)*1.0*y*(n-x)):0.0;
	f[x][y]+=(x&&y)?(dfs(x-1,y-1)*1.0*x*y):0.0; 
	return f[x][y]=(f[x][y]+n*n*1.0)/((x+y)*n-x*y);
}

int main()
{
	read(n),read(m);
	for(int i=1;i<=m;i++)
	{
		int x,y;
		read(x),read(y);
		heng[x]=zong[y]=1;
	}
	for(int i=1;i<=n;i++) hang+=!heng[i],lie+=!zong[i];
	for(int i=0;i<=n;i++)
	for(int j=0;j<=n;j++)
	f[i][j]=-1;
	
	printf("%.2lf",dfs(hang,lie));
	return 0;
}

T2 有趣的数列

题解:

卡特兰数+质因数分解

\(code:\)

#include<cstdio> 
#include<algorithm> 
#include<ctype.h>  
#include<vector> 
#include<queue> 
#include<cstring> 
#define lowbit(x) (x&-x) 
#define ll long long 
#define ld double 
#include<map> 
#include<stdlib.h> 
#include<ctime> 
using namespace std; 

char buf[1<<20],*p1,*p2; 
inline char gc() 
{ 
//    return getchar(); 
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++; 
} 

template<typename T> 
inline void read(T &x) 
{ 
    char tt; 
    bool flag=0; 
    while(!isdigit(tt=gc())&&tt!='-'); 
    tt=='-'?(flag=1,x=0):(x=tt-'0'); 
    while(isdigit(tt=gc())) x=x*10+tt-'0'; 
    if(flag) x=-x; 
} 

const int maxn=1000002;
ll pri[maxn<<1],phi[maxn<<1],s[maxn<<1],ans=1;
ll n,mod,tot;
bool book[maxn<<1];

void modify(int x,int d){
    while(1){
    	if(pri[phi[x]]==0) break;
        s[phi[x]]+=d;
        x/=pri[phi[x]];
    }
}

void sent(){
    for(int i=2;i<=n<<1;i++){
        if(!book[i]) pri[++tot]=i,phi[i]=tot;
        for (int j=1;pri[j]*i<=(n<<1)&&j<=tot;j++){
            book[pri[j]*i]=1,phi[pri[j]*i]=j;
            if(i%pri[j]==0) break;
        }
    }
}

int main(){
// 1 1 5 14 42 
//	freopen("interesting.in","r",stdin);
//	freopen("interesting.out","w",stdout);
   	read(n),read(mod);sent();
    for (int i=n<<1;i>n;i--) modify(i,1);
    for (int i=1;i<=n;i++) modify(i,-1);
    modify(n+1,-1);
    for(int i=1;i<=tot;i++)
	while(s[i]--) ans=(ans*pri[i])%mod;
    
	printf("%lld",ans);
	return 0;
}

T3 距离

题解:

·手推可得\(d(a,b)=div(a)+div(b)-div(gcd(a,b))*2\),\(div\)\(a,b\)的质因数指数和;

·\(O(N^2)\)暴力肯定是不可行的,因为质因数个数最多\(200\)多个,因此我们考虑枚举\(gcd\);

·我们用\(f1[k],f2[k]\)分别记下当某数为\(k\)倍数时的最小编号,次小编号;

(因为编号不可为同一个数)

·统计答案时,显然这时\(div(x)\)为定值,\(O(\sqrt{N})\)分解质因数,统计记录最小的\(div(k)-div(x)*2\)的值,更新最小编号\(id=min(id,k)\);

(其中\(k=(f1[x]==i)?f2[x]:f1[x]\);\(x\)为枚举出的因数)

\(code:\)

#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn=1000002;
int n,a[maxn],tot;
int pri[maxn],cnt[maxn];
int f1[maxn],f2[maxn];
bool book[maxn];
void sent()
{
	for(int i=2;i<=maxn-1;i++)
	{
		if(!book[i])
		{
			pri[++tot]=i;
			cnt[i]=1;
		}
		for(int j=1;j<=tot&&i*pri[j]<=maxn-1;j++)
		{
			book[i*pri[j]]=1,cnt[i*pri[j]]=cnt[i]+1;
			if(i%pri[j]==0) break;
		}
	}
}

void update(int i,int gcd)
{
	if(cnt[a[i]]<=cnt[a[f1[gcd]]])
	f2[gcd]=f1[gcd],f1[gcd]=i;
	else if(cnt[a[i]]<=cnt[a[f2[gcd]]]) f2[gcd]=i;
}

void getf()
{
	for(int i=n;i>=1;i--)
	{
		for(int j=1;j*j<=a[i];j++)
		if(a[i]%j==0)
		{
			update(i,j);
			if(j*j!=a[i]) update(i,a[i]/j);
		}
	}
}

int main()
{
	sent();
	scanf("%d",&n);cnt[0]=1e9;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);getf();
	for(int i=1;i<=n;i++)
	{
		int id=1e9,ans=1e9;
		for(int j=1;j*j<=a[i];j++)
		if(a[i]%j==0)
		{
			int x=j,k;
			if(f1[x]!=i) k=f1[x];else k=f2[x];
			if(ans>cnt[a[k]]-(cnt[x]<<1)||((ans==cnt[a[k]]-(cnt[x]<<1))&&id>k))
			ans=cnt[a[k]]-(cnt[x]<<1),id=k;
			
			if(j*j==a[i]) continue;
			
			x=a[i]/j;
			if(f1[x]!=i) k=f1[x];else k=f2[x];
			if(ans>cnt[a[k]]-(cnt[x]<<1)||((ans==cnt[a[k]]-(cnt[x]<<1))&&id>k))
			ans=cnt[a[k]]-(cnt[x]<<1),id=k;
		}
		printf("%d\n",id);
	}
}
posted @ 2018-10-18 23:44  Katoumegumi  阅读(68)  评论(0编辑  收藏  举报
返回顶部