博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

11.7 NOIP模拟赛


2018.11.7 NOIP模拟

时间:3.5h
期望得分:100+0+40
实际得分:100+0+40

A 序列sequence(two pointers)

其实我们只要处理每个数与哪些数相加,会产生进位就行了。
把数排序后,枚举一个数x,容易想到满足使x+y进位的y是单调的(要求y<=x)。所以可以二分。
但是单调,好像只需要two pointers就可以了?但比如10 100 990 9900,好像不单调了(990与9900)?
事实上只要对位数相同的算就可以了,即最多只算8段,这一段中数的位数相同,然后令l=1,向r移动;r=j,向i移动,对每个r计算答案就行了(i,j是有相同位数的数的这一段的左右端点)。
复杂度\(O(n\log n+n)\)

#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define Count(x) (x>100000?bit[(x)/100000]+5:bit[x])
typedef long long LL;
const int N=1e6+5;

int A[N],bit[100005],pw[233];
char IN[MAXIN],*SS=IN,*TT=IN;

inline int read()
{
	int now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now;
}

int main()
{
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);

	pw[0]=1;
	for(int i=1; i<=9; ++i) pw[i]=pw[i-1]*10;
	for(int i=1; i<=100000; ++i) bit[i]=bit[i/10]+1;
	int n=read(); LL ans=0;
	for(int i=1; i<=n; ++i) A[i]=read();
	std::sort(A+1,A+1+n), A[n+1]=1e9;
	for(int i=1,x,y,las=1; i<=n; ++i)
	{
		y=Count(A[i]), ans+=y*(i-1);
		if(y!=Count(A[i+1]))
		{
			int l=1,r=i;
			while(l<r && r>=las)
			{
				while(l<r && A[l]<pw[y]-A[r]) ++l;
				ans+=r-l, --r;
			}
			las=i+1;
		}
	}
	printf("%I64d\n",ans);

	return 0;
}

B 锁lock(思路)

模拟一下样例,也就是我们知道了一共6个钥匙:
首先对于1 2,他们合起来不能有所有钥匙,所以假设他们都没有钥匙1;
同理对于1 3,假设他们都没有钥匙2...
而如果2个人的情况满足了,1个人显然不能凑够6把钥匙。
这样把所有\(m-1\)个人的组合都分配一遍,正好是6。所以在\(A_i=1\)时,答案应该是\(C_n^{m-1}\)
那么\(A_i\neq1\)时呢?
同理,对于极大的重要度不足\(m\)的一个集合\(s\),我们要令他们都没有某一个钥匙。然后对于\(s\)的所有子集都已经满足条件,之后就不需要枚举了。
\(2^n\)枚举集合,判一下有多少极大的重要度不足\(m\)的集合,就知道要有多少个钥匙了。
(极大的是指,该集合加入任意一个该集合外的元素,重要度都\(\geq m\)。)

复杂度\(O(n*2^n)\)
注意所有\(Ai\)的和不足\(m\)时输出\(1\),因为所有人也不能满足。

mjtnb!mjtAKxxxP!

#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=23;

int A[N];

inline int read()
{
	int now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now;
}

int main()
{
	freopen("lock.in","r",stdin);
	freopen("lock.out","w",stdout);

	int n=read(),m=read(); LL s=0;
	for(int i=0; i<n; ++i) s+=A[i]=read();
	if(s<m) return printf("1\n"),0;
	int ans=0;
	for(int s=0,lim=1<<n; s<lim; ++s)
	{
		int sum=0,mn=1e9;
		for(int i=0; i<n; ++i) s>>i&1?(sum+=A[i]):(mn=std::min(mn,A[i]));
		ans+=(sum<m&&sum+mn>=m);
	}
	printf("%d\n",ans);

	return 0;
}

C 正方形square(埃氏筛)

莫比乌斯反演推出50分做法了,想错复杂度没写,sad(好像没什么用)。
忘掉欧拉函数了。




最后一步没看懂,贴std:

# include <bits/stdc++.h>
#define ll long long
using namespace std;
const int T=1e7, N=1e7 + 10, P=19260817;
int sum[N], use[N], mul[N];
int power(int x, int y){
    int i=x; x=1;
    while (y > 0){
        if (y%2 == 1) x=1ll*x*i%P;
        i=1ll*i*i%P;
        y /= 2;
    }
    return x;
}
void pre(){
    use[1]=true;
    for (int i=0; i<=T; i++) sum[i]=1;
    for (int i=2; i<=T; i++)
        if (use[i] == false){
            ll t=i;
            for (int k=1; t<=T; k++, t*=i){//t=i^k
                for (int tmp=t, num=i; tmp<=T; tmp+=t, num=1ll*num*i%P*i%P)
                    sum[tmp]=1ll*sum[tmp]*num%P;
            }
            for (int k=i; k<=T; k+=i) use[k]=true;
        }
    for (int i=1; i<=T; i++) sum[i]=1ll*sum[i-1]*sum[i]%P;
    for (int i=1; i<=T; i++) sum[i]=1ll*sum[i]*sum[i]%P;
    mul[0]=1; for (int i=1; i<=T; i++) mul[i]=1ll*mul[i-1]*i%P;
}
int main(){
	freopen("square.in","r",stdin);;
	freopen("square.out","w",stdout);
    pre();
    std::ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int opt;cin>>opt;
    while (opt--){
        int n;cin>>n;
        int tmp=R1ll*power(mul[n], 2*n)*power(sum[n], P-2)%P;
        cout<<tmp<<'\n';
    }
    return 0;
}

考试代码

B

自闭。

#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=23;

int A[N];

inline int read()
{
	int now=0,f=1;register char c=gc();
	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now*f;
}

int main()
{
	freopen("lock.in","r",stdin);
	freopen("lock.out","w",stdout);

	int n=read(),m=read();
	for(int i=1; i<=n; ++i) A[i]=read();
	if(n==4&&m==3) return printf("6"),0;
	if(n==4&&m==2) return printf("4"),0;
	if(n==3&&m==2) return printf("2"),0;
	if(n==1||m==1) return printf("1"),0;
	if(n==m) return printf("%d",n),0;
	printf("%I64d\n",1ll*(n-2)*m);

	return 0;
}

C

/*
我好像只会
O(Tn^2\log)
O(n^2+T\log)
O(n\sqrt(n)+T\log)
所以这是什么奇怪的部分分。
*/
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define mod 19260817
#define Inv(x) FP(x,mod-2)
typedef long long LL;
const int N=1e7+5;

int fac[N],inv[mod+4],prod[N];
char IN[MAXIN],*SS=IN,*TT=IN,OUT[10000000],*O=OUT;

inline int read()
{
	int now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now;
}
inline void Print(int x)
{
	static char sk[10];
	int t=0;
	while(x) sk[t++]=x%10+'0',x/=10;
	while(t--) *O++=sk[t];
	*O++='\n';
}
inline int FP(int x,int k)
{
	int t=1;
	for(; k; k>>=1,x=1ll*x*x%mod)
		k&1&&(t=1ll*t*x%mod);
	return t;
}
int Gcd(int x,int y)
{
	return y?Gcd(y,x%y):x;
}

int main()
{
	freopen("square.in","r",stdin);
	freopen("square.out","w",stdout);

	fac[0]=fac[1]=1, inv[1]=1;
	for(int i=2; i<=10000001; ++i) fac[i]=1ll*fac[i-1]*i%mod;
	for(int i=2; i<mod; ++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
	prod[1]=1;
	for(int i=2; i<=1000; ++i)
	{
		LL tmp=prod[i-1];
		for(int j=2,g; j<i; ++j) g=Gcd(i,j), g=inv[1ll*g*g%mod], tmp=tmp*g%mod*g%mod;
		prod[i]=tmp*inv[1ll*i*i%mod]%mod;
//		for(int j=2,g; j<i; ++j) g=Gcd(i,j), tmp=tmp*(g*g%mod);
//		prod[i]=tmp*(i*i%mod)%mod;
	}
//	for(int i=1; i<=30; ++i) printf("prod[%d]=%d\n",i,prod[i]);
//	return 0;

	for(int T=read(); T--; )
	{
		int n=read();
		Print(1ll*FP(fac[n],n<<1)*prod[n]%mod);
	}
	fwrite(OUT,O-OUT,1,stdout);

	return 0;
}
posted @ 2018-11-07 21:08  SovietPower  阅读(204)  评论(0编辑  收藏  举报