11.5NOIP2018提高组模拟题

书信(letter)

Description

有 n 个小朋友, 编号为 1 到 n, 他们每人写了一封信, 放到了一个信箱里, 接下来每个人从中抽取一封书信。 显然, 这样一共有 n!种拿到书信的情况。

现在亮亮规定, 对任意的 1<=x,y<=n, 如果 x 号小朋友拿到 u 号小朋友写的 书信, y 号小朋友拿到 v 号小朋友写的书信, 那么(x+y)号小朋友必须拿到(u+v) 号小朋友写的书信(这里的加法若和超过了 n, 那么就减去 n) 。

小林想知道, 总共有多少种拿到书信的情况呢?

Input

只有一行一个正整数 n。

Output

只有一行一个正整数, 表示符合条件的情况的总数。

这题感觉不太可证明,自己不会

通过枚举全排列打表发现,这题就是一个裸的求(phi(n))

(O(sqrt{n}))(phi(n))的话就不多(BB)了 。

这里放一下公式。

[phi(x)=x imes prod_{i=1}^{r} (1-frac{1}{p_i}) ]

然后直接去求然后输出即可。

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#define int long long 
#define R register

using namespace std;

inline void in(R int &x)
{
	int f=1;x=0;char s=getchar();
	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
	x*=f;
}

int n;

inline int phi(int x)
{
    int res=x;
    for(int i=2;i*i<=x;i++)
    {
        if(x%i==0)
        {
            res=res/i*(i-1);
            while(x%i==0)x/=i;
        }
    }
    if(x>1)res=res/x*(x-1);
    return res;
}


signed main()
{
	freopen("letter.in","r",stdin);
	freopen("letter.out","w",stdout);
	
	in(n);
	printf("%lld
",phi(n));

	fclose(stdin);
	fclose(stdout);
	
	return 0;
}

金条(au)

Description

小林在一家商店里购物, 共有 i 件物品, 第 i 件物品的价格为 i。 小林身上带 了许多金条, 每根金条的价值都为整数, 价值为 1~N 的金条数量都足够多。

对于任何一件物品,小林只会用同一价值的若干金条购买它,而且不能找零。 因此, 对于第 i 件物品, 会有 C(i)种购买方法。 小林只会选择这样的一件物品 i 进行购买: C(i) > max{ C(j) }, 1 <= j < i。

请你告诉小林, 他能购买的最贵的物品的价格是多少。

Input

只有一行一个整数 N。

Output

只有一个整数, 表示答案。

通过读题可以发现,我们是求(1)(n)之间的约数个数最多的数。

PS:如果两个数的约数个数相同,取较小的一个。

有一个结论:可以求一个数的约数个数。

首先根据唯一分解定理(其中(p_1)是素数)

[x=p_1^{k_1} imes p_2^{k_2} imes p_3^{k_3} imes dots ]

那么一个数的约数个数就是这个:

[d(x)=(k_1+1) imes(k_2+1) imes dots ]

(d(x))表示(x)的约数个数。

然后通过计算可以知道,在(2 imes 10^9)中不同的质数的个数不会超过(10)个.

因此我们写出前(10)个素数.

然后直接暴力搜索即可。

注意:两个数的约数个数相同的话,取较小的一个。

题目要求严格(>)

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#define int long long
#define R register

using namespace std;

inline void in(int &x)
{
	int f=1;x=0;char s=getchar();
	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
	x*=f;
}
int prime[20]={0,2,3,5,7,11,13,17,19,23,29,31,37,41};
int ans,mx,n;
void dfs(R int dep,R int now,R int cnt)
{
	if(dep>=11)return;		
	if(cnt>mx)mx=cnt,ans=now;
	if(cnt==mx and ans>now)ans=now;
	for(R int i=1;i<=32;i++)
	{
		if(now*prime[dep]>n)break;
		dfs(dep+1,now*=prime[dep],cnt*(i+1));
	}
}
signed main()
{
	freopen("au.in","r",stdin);
	freopen("au.out","w",stdout);
	
	in(n);
	dfs(1,1,1);
	printf("%lld",ans);
	
	fclose(stdin);
	fclose(stdout);
	
	return 0;
}

小朋友(friend)

Description

n 个小朋友在一起做游戏, 第 i 个小朋友的快乐值为 Di。 当第 i 个小朋友和 第 j 个小朋友一起玩时, 他们能获得 Di xor Dj 的快乐值。 每一个小朋友 i 都 想知道, 他和谁一起玩能够获得最大的快乐值, 请你帮他们每个人分别求出这个 值。

Input

第一行有一个整数 (n)。 第二行三个整数 (K, B, P)(1≤K≤20)(0≤B<2^{16})(0≤P<2^{24})) 。 根据 $ D_i = (K imes D_{i-1} + B)%2^{24}$ 和 (D_1 = P) 自行计算整个 (P) 数组 。

Output

一个整数 (Ans)(Ans=(sum_{i=1}^{n} 3^{i-1} imes Ans_i)%2^{24}) 。 其中 (Ans_i) 表示对于第 i 个小朋友 我们需要的答案。

表示看到异或,还是取两两异或的最大值,选择树(01Trie)

这个东西网上讲解很多,不多(BB).

我们将得到的(D_i)插入到(Trie)树中。

查询就普通查询(贪心)即可。

时限由于有(5s)所以怎么搞都行。

注意不要傻到每次(ksm)(3^{i-1})

可以预处理,可以用一个变量。(这里我用了预处理)

这可以说是一个裸题?

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#define mod 16777216
#define lo long long 
#define R register

using namespace std;

const int gz=2e6+5;

inline void in(R lo &x)
{
	int f=1;x=0;char s=getchar();
	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
	x*=f;
}

lo n,K,B,P,ans;
lo a[gz],po[gz]={1};

struct Trie
{
	int ch[gz*15][2],idx;
	
	inline void ins(R int x)
	{
		R int u=0;
		for(R int i=25;i>=0;i--)
		{
			R int bit=(x>>i)&1LL;
			if(!ch[u][bit])ch[u][bit]=++idx;
			u=ch[u][bit];
		}
	}
	inline int query(R int x)
	{
		R int u=0,res=0;
		for(R int i=25;i>=0;i--)
		{
			R int bit=(x>>i)&1LL;
			if(ch[u][bit^1])
			{
				res+=(1LL<<i);
				u=ch[u][bit^1];
			}
			else u=ch[u][bit];
		}
		return res;
	}
}woc;

int main()
{
	freopen("friend.in","r",stdin);
	freopen("friend.out","w",stdout);
	
	in(n);in(K),in(B),in(P);a[1]=P%mod;woc.ins(a[1]);
	for(R int i=1;i<=n;i++)po[i]=po[i-1]*3%mod;
	for(R int i=2;i<=n;i++)
	{
		a[i]=((K*a[i-1])%mod+B)%mod;
		woc.ins(a[i]%mod);
	}
	for(R int i=1;i<=n;i++)
		(ans+=po[i-1]*woc.query(a[i])%mod)%=mod;
	printf("%lld
",(ans+mod)%mod);
}
原文地址:https://www.cnblogs.com/-guz/p/9907944.html