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;
}
很久以前的奇怪但现在依旧成立的签名
attack is our red sun $$\color{red}{\boxed{\color{red}{attack\ is\ our\ red\ sun}}}$$ ------------------------------------------------------------------------------------------------------------------------