JNU第三场训练赛题解

A.模拟即可

#include
#include
using namespace std;
int a[150]; 
int main()
{
	//freopen("5.txt","r",stdin);
	//freopen("5.out","w",stdout);
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		a[2*i-1]=i;
	int w=2*n-2;
	int t=2*n-1;
	while(w)
	{
		while(a[t]==0)t--;
		a[w]=a[t--];
		w-=2;
	}
	for(int i=1;i<=n;i++)
		printf("%d",a[i]);
	puts("");
}

B.简单数论

第N个素数是什么,N<=1226564

预处理素数打表,把埃筛预处理23000000以上卡掉,

其实可以先预处理5e7,跑数据上限,1226564个素数刚好是19260827,然后调预处理范围

或者素数定理n/lnn近似=1226564,解一下n 

埃氏700ms,线筛231ms


#include
#include
#include
using namespace std;

int pri[1300000];
int isp[22000001];
int p=0;
void init(int n)//线性筛 237ms 对每个最大因子i枚举最小素因子,筛其乘积,无重复筛 O(n)
{
	for(int i=2;i<=n;i++)
	{
		if(isp[i]==0)
			pri[++p]=i;
		for(int j=1;j<=p&&i*pri[j]<=n;j++)
		{
			if(i<=100) 
			//	printf("最大因数i:%d,mul:%d ,最小素因子p:%d\n",i,i*pri[j],pri[j]);
			isp[i*pri[j]]=1;
			if(i%pri[j]==0)break;//最小素因子不可能比最大因数大 
		}
	}
} 
int initPP(int n) //欧拉筛 700ms  筛去素数的倍数 ,有重复筛,比如6=2x3 O(nloglogn) 
{   int p=0;
    for(int i = 2; i <= n; i ++) isp[i] = true;
    for(int i = 2; i <= n; i ++) //判断改成i*i>k;
	cout<

C.思维/DP

n,m太小,没卡算法

dp解最快,暴力好像也可以过

但如果n,m<=1e12就把dp,大数,暴力都卡掉了

ans=C(m+n,n)%19260817

比如n=2,m=3;一共要走5步,5步选其中选2步向上走,那么有C(5,2)=10种取法

大组合数取模用卢卡斯定理+逆元解只要O(logp(n))*p


D.思维+矩阵快速幂

白书203改

hupo用的DP解,贴一发他的代码,太强了orz

#include
#include
#include
#include
#include
#include
using namespace std;
int dp[105][20];
vectorG[105];
int main()
{
	int n,m,k;
	cin>>n>>m>>k;
	int from,to;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&from,&to);
		G[from].push_back(to);
	}
	for(int i=1;i<=n;i++)
	{
		dp[i][0]=1;	
	}
	for(int i=1;i<=k;i++)
	{
		for(int j=1;j<=n;j++)
		{
			for(int z=0;z

这题k=1e12也能做,先把图转换成邻接矩阵M,M就是k=1的解  ,ans=M^k,16ms

#include
#include
#include
using namespace std;
#define ll long long
const int maxn=105;
const int mod=19260817;
struct mat
{
	ll m[maxn+1][maxn+1];
};
mat operator *(mat a,mat b)
{
	mat res;
	for(int i=1; i<=maxn; i++)
		for(int j=1; j<=maxn; j++)
			res.m[i][j]=0;
	for(int i=1; i<=maxn; i++)
		for(int j=1; j<=maxn; j++)
		{
			for(int k=1; k<=maxn; k++)
				res.m[i][j]+=1ll*(a.m[i][k])*(b.m[k][j])%mod;
			res.m[i][j]%=mod;
		}

	return res;
}

mat qmod(mat a,ll b)
{
	mat res;
	for(int i=1; i<=maxn; i++)
		for(int j=1; j<=maxn; j++)
			res.m[i][j]=0,res.m[i][i]=1;
	while(b)
	{
		if(b&1)	res=res*a;
		a=a*a;  b=b>>1;
	}
	return res;
}
void init(mat &mmm)
{
    for(int i=1; i<=maxn; i++)
        for(int j=1; j<=maxn; j++)
            mmm.m[i][j]=0;
}
int main()
{
	mat a;
	for(int i=1; i<=maxn; i++)
		for(int j=1; j<=maxn; j++)
			a.m[i][j]=0;//必须加这个!!!分配内存,不能直接cin 
//	freopen("6.txt","r",stdin);
//	freopen("6.out","w",stdout);
	int n,m,k;
	cin>>n>>m>>k; int u,v;
	for(int i=1; i<=m; i++)
	{
		scanf("%d %d",&u,&v);
		a.m[u][v]=1;
	}
	mat c=qmod(a,k);
	ll ans=0;
	for(int i=1; i<=n; i++)
	{
		for(int j=1; j<=n; j++)
		{
			ans+=c.m[i][j];	
			ans%=mod;
		}	
	}
	cout<


E.数论还行

分别预处理d(i),f(i)然后跑一遍即可,预处理最大,最小质因子都可以直接花式埃筛,最小质因子用线性筛最快

复杂度O(n+nloglogn+n),O(n+nloglogn+nlogn)也能过

E把预处理素数后对每个数sqrt(i)找di,fi的做法卡掉了

216ms

#include
#include
#include
using namespace std;
#define ll long long
int pri[1000000];
int isp[5000001];
int p=0;
int dd[5000005];
void initline(int n)//min p  On  线筛找最小质因子,不会这个写init2也能过。 
{
	for(int i=2;i<=n;i++)
	{
		if(isp[i]==0)
		{
			pri[++p]=i;
			dd[i]=i;	
		}
		for(int j=1;j<=p&&i*pri[j]<=n;j++)
		{
			//	if(i<=100) 
			//	printf("最大因数i:%d,mul:%d ,最小素因子p:%d\n",i,i*pri[j],pri[j]);
			isp[i*pri[j]]=1;
			dd[i*pri[j]]=pri[j];
			if(i%pri[j]==0)break;//最小素因子不可能比最大因数大 
		}
	}
} 
int d[5000005];
void init2(int n)//min p Onlogn 
{
	for(int i=n; i>=2; i--)
	{
		if(!d[i])
			for(int j=i; j<=n; j+=i)
				d[j]=i;
	}
}
int f[5000005];
void init(int n)//max p   Onloglogn
{
	for(int i=2; i<=n; i++)
	{
		if(!f[i])
			for(int j=i; j<=n; j+=i)
				f[j]=i;
	}
}


int main()
{
//	freopen("5.txt","r",stdin);
//	freopen("5.out","w",stdout);
	int x;
	cin>>x;
	init(5000001); 
//	printf("%.2f\n", (double)clock()/CLOCKS_PER_SEC);
	init2(5000000); 
//	printf("%.2f\n", (double)clock()/CLOCKS_PER_SEC);
//	initline(5000001);
//	printf("%.2f\n", (double)clock()/CLOCKS_PER_SEC);
	ll ans=0;
//	printf("%d %d",f[7],dd[7]);
	for(int i=2;i<=x;i++)
		ans+=1ll*(d[i]^f[i]);
	cout<





你可能感兴趣的:(JNU第三场训练赛题解)