牛客练习赛53 部分题解
A、签到,暴力打个表就发现规律是斐波那契数列
代码:
#include <bits/stdc++.h>
#define int long long
#define sc(a) scanf("%lld",&a)
#define scc(a,b) scanf("%lld %lld",&a,&b)
#define sccc(a,b,c) scanf("%lld %lld %lld",&a,&b,&c)
#define scs(a) scanf("%s",a)
#define schar(a) scanf("%c",&a)
#define pr(a) printf("%lld",a)
#define fo(i,a,b) for(int i=a;i<b;++i)
#define re(i,a,b) for(int i=a;i<=b;++i)
#define rfo(i,a,b) for(int i=a;i>b;--i)
#define rre(i,a,b) for(int i=a;i>=b;--i)
#define prn() printf("\n")
#define prs() printf(" ")
#define mkp make_pair
#define pii pair<int,int>
#define pub(a) push_back(a)
#define pob() pop_back()
#define puf(a) push_front(a)
#define pof() pop_front()
#define fst first
#define snd second
#define frt front()
#define bak back()
#define mem0(a) memset(a,0,sizeof(a))
#define memmx(a) memset(a,0x3f3f,sizeof(a))
#define memmn(a) memset(a,-0x3f3f,sizeof(a))
#define debug
#define db double
#define yyes cout<<"YES"<<endl;
#define nno cout<<"NO"<<endl;
#define all(i,a) for(auto i=a.begin();i!=a.end();++i)
using namespace std;
typedef vector<int> vei;
typedef vector<pii> vep;
typedef map<int,int> mpii;
typedef map<char,int> mpci;
typedef map<string,int> mpsi;
typedef deque<int> deqi;
typedef deque<char> deqc;
typedef priority_queue<int> mxpq;
typedef priority_queue<int,vector<int>,greater<int> > mnpq;
typedef priority_queue<pii> mxpqii;
typedef priority_queue<pii,vector<pii>,greater<pii> > mnpqii;
const int maxn=500005;
const int inf=0x3f3f3f3f3f3f3f3f;
const int MOD=1e9+7;
const db eps=1e-10;
const db pi=3.1415926535;
int qpow(int a,int b){int tmp=a%MOD,ans=1;while(b){if(b&1){ans*=tmp,ans%=MOD;}tmp*=tmp,tmp%=MOD,b>>=1;}return ans;}
int lowbit(int x){return x&-x;}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
int mmax(int a,int b,int c){return max(a,max(b,c));}
int mmin(int a,int b,int c){return min(a,min(b,c));}
void mod(int &a){a+=MOD;a%=MOD;}
bool chk(int now){}
int half(int l,int r){while(l<=r){int m=(l+r)/2;if(chk(m))r=m-1;else l=m+1;}return l;}
int ll(int p){return p<<1;}
int rr(int p){return p<<1|1;}
int mm(int l,int r){return (l+r)/2;}
int lg(int x){if(x==0) return 1;return (int)log2(x)+1;}
bool smleql(db a,db b){if(a<b||fabs(a-b)<=eps)return true;return false;}
bool bigeql(db a,db b){if(a>b||fabs(a-b)<=eps)return true;return false;}
bool eql(db a,db b){if(fabs(a-b)<eps) return 1;return 0;}
db len(db a,db b,db c,db d){return sqrt((a-c)*(a-c)+(b-d)*(b-d));}
bool isp(int x){if(x==1)return false;if(x==2)return true;for(int i=2;i*i<=x;++i)if(x%i==0)return false;return true;}
inline int read(){
char ch=getchar();int s=0,w=1;
while(ch<48||ch>57){if(ch=='-')w=-1;ch=getchar();}
while(ch>=48&&ch<=57){s=(s<<1)+(s<<3)+ch-48;ch=getchar();}
return s*w;
}
inline void write(int x){
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+48);
}
int gcd(int a, int b){
if(a==0) return b;
if(b==0) return a;
if(!(a&1)&&!(b&1)) return gcd(a>>1,b>>1)<<1;
else if(!(b&1)) return gcd(a,b>>1);
else if(!(a&1)) return gcd(a>>1,b);
else return gcd(abs(a-b),min(a,b));
}
int lcm(int x,int y){return x*y/gcd(x,y);}
int f[maxn];
signed main(){
ios_base::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n;cin>>n;
f[1]=2,f[2]=3;
re(i,3,n)
f[i]=(f[i-1]+f[i-2])%MOD;
cout<<f[n];
return 0;
}
B、
要求下面这个怪怪公式:
\(\Sigma_{i=1}^n\Sigma_{j=1}^ii* {\lfloor \frac{i}{j} \rfloor}^j\)
范围n<=3000000,看起来似乎可以有\(O(n \sqrt{n} )\)的做法,比较直观的想法就是数论分块,枚举 \(i\) 即可
数论分块参见数论分块
但是果然T了,跑了百分之六十的数据。
现在得换种思路,枚举 \(j\) ,把 \(\frac{i}{j}\) 拿出来打表看看,会发现下面这个怪东西:
于是分成了长度为 \(j\) 的块,时间复杂度是\(O(n \ln{n} )\),调和级数确实牛批
另外还可以考虑把快速幂优化掉,每一次只维护一个数组,储存对应数字的 \(j\) 次方即可,需要的时候再让他乘以 \(j\)
代码:
#include <bits/stdc++.h>
#define int long long
#define sc(a) scanf("%lld",&a)
#define scc(a,b) scanf("%lld %lld",&a,&b)
#define sccc(a,b,c) scanf("%lld %lld %lld",&a,&b,&c)
#define scs(a) scanf("%s",a)
#define schar(a) scanf("%c",&a)
#define pr(a) printf("%lld",a)
#define fo(i,a,b) for(int i=a;i<b;++i)
#define re(i,a,b) for(int i=a;i<=b;++i)
#define rfo(i,a,b) for(int i=a;i>b;--i)
#define rre(i,a,b) for(int i=a;i>=b;--i)
#define prn() printf("\n")
#define prs() printf(" ")
#define mkp make_pair
#define pii pair<int,int>
#define pub(a) push_back(a)
#define pob() pop_back()
#define puf(a) push_front(a)
#define pof() pop_front()
#define fst first
#define snd second
#define frt front()
#define bak back()
#define mem0(a) memset(a,0,sizeof(a))
#define memmx(a) memset(a,0x3f3f,sizeof(a))
#define memmn(a) memset(a,-0x3f3f,sizeof(a))
#define debug
#define db double
#define yyes cout<<"YES"<<endl;
#define nno cout<<"NO"<<endl;
#define all(i,a) for(auto i=a.begin();i!=a.end();++i)
using namespace std;
typedef vector<int> vei;
typedef vector<pii> vep;
typedef map<int,int> mpii;
typedef map<char,int> mpci;
typedef map<string,int> mpsi;
typedef deque<int> deqi;
typedef deque<char> deqc;
typedef priority_queue<int> mxpq;
typedef priority_queue<int,vector<int>,greater<int> > mnpq;
typedef priority_queue<pii> mxpqii;
typedef priority_queue<pii,vector<pii>,greater<pii> > mnpqii;
const int maxn=3000005;
const int inf=0x3f3f3f3f3f3f3f3f;
const int MOD=1e9+7;
const db eps=1e-10;
const db pi=3.1415926535;
int qpow(int a,int b){int tmp=a%MOD,ans=1;while(b){if(b&1){ans*=tmp,ans%=MOD;}tmp*=tmp,tmp%=MOD,b>>=1;}return ans;}
int lowbit(int x){return x&-x;}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
int mmax(int a,int b,int c){return max(a,max(b,c));}
int mmin(int a,int b,int c){return min(a,min(b,c));}
void mod(int &a){a+=MOD;a%=MOD;}
bool chk(int now){}
int half(int l,int r){while(l<=r){int m=(l+r)/2;if(chk(m))r=m-1;else l=m+1;}return l;}
int ll(int p){return p<<1;}
int rr(int p){return p<<1|1;}
int mm(int l,int r){return (l+r)/2;}
int lg(int x){if(x==0) return 1;return (int)log2(x)+1;}
bool smleql(db a,db b){if(a<b||fabs(a-b)<=eps)return true;return false;}
bool bigeql(db a,db b){if(a>b||fabs(a-b)<=eps)return true;return false;}
bool eql(db a,db b){if(fabs(a-b)<eps) return 1;return 0;}
db len(db a,db b,db c,db d){return sqrt((a-c)*(a-c)+(b-d)*(b-d));}
bool isp(int x){if(x==1)return false;if(x==2)return true;for(int i=2;i*i<=x;++i)if(x%i==0)return false;return true;}
inline int read(){
char ch=getchar();int s=0,w=1;
while(ch<48||ch>57){if(ch=='-')w=-1;ch=getchar();}
while(ch>=48&&ch<=57){s=(s<<1)+(s<<3)+ch-48;ch=getchar();}
return s*w;
}
inline void write(int x){
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+48);
}
int gcd(int a, int b){
if(a==0) return b;
if(b==0) return a;
if(!(a&1)&&!(b&1)) return gcd(a>>1,b>>1)<<1;
else if(!(b&1)) return gcd(a,b>>1);
else if(!(a&1)) return gcd(a>>1,b);
else return gcd(abs(a-b),min(a,b));
}
int lcm(int x,int y){return x*y/gcd(x,y);}
int n,inv=qpow(2,MOD-2),ans=0;
int p[maxn];
int s(int l,int r){return (((r+l)*(r-l+1)%MOD)*inv)%MOD;}
signed main(){
ios_base::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
re(i,1,n) p[i]=i;
re(j,1,n){
int flag=1;
for(int i=j;i<=n;i+=j){
ans=(ans+s(i,min(i+j-1,n))*p[flag]%MOD)%MOD;
p[flag]=(p[flag]*flag%MOD)%MOD;
flag++;
}
}
cout<<ans;
return 0;
}
C、一开始以为是什么怪怪通配符匹配,没想到是bitset大胜利
对于每个询问维护两个bitset,不妨设为A和B,如果该位是通配符,那么\(A[i]=B[i]=0\)
否则的话\(A[i]=1 B[i]=S[i]\),\(S[i]\)是读入的数组
这样有什么好处呢?我们令\(A \& bs[i]\),其中\(bs[i]\)是输入的字典,会发现通配符位置上是一定匹配的,而其他位置仍保持原状,比较一下是否相等即可
时间复杂度\(O(n^2)\)
代码:
#include <bits/stdc++.h>
#define int long long
#define sc(a) scanf("%lld",&a)
#define scc(a,b) scanf("%lld %lld",&a,&b)
#define sccc(a,b,c) scanf("%lld %lld %lld",&a,&b,&c)
#define scs(a) scanf("%s",a)
#define schar(a) scanf("%c",&a)
#define pr(a) printf("%lld",a)
#define fo(i,a,b) for(int i=a;i<b;++i)
#define re(i,a,b) for(int i=a;i<=b;++i)
#define rfo(i,a,b) for(int i=a;i>b;--i)
#define rre(i,a,b) for(int i=a;i>=b;--i)
#define prn() printf("\n")
#define prs() printf(" ")
#define mkp make_pair
#define pii pair<int,int>
#define pub(a) push_back(a)
#define pob() pop_back()
#define puf(a) push_front(a)
#define pof() pop_front()
#define fst first
#define snd second
#define frt front()
#define bak back()
#define mem0(a) memset(a,0,sizeof(a))
#define memmx(a) memset(a,0x3f3f,sizeof(a))
#define memmn(a) memset(a,-0x3f3f,sizeof(a))
#define debug
#define db double
#define yyes cout<<"YES"<<endl;
#define nno cout<<"NO"<<endl;
#define all(i,a) for(auto i=a.begin();i!=a.end();++i)
using namespace std;
typedef vector<int> vei;
typedef vector<pii> vep;
typedef map<int,int> mpii;
typedef map<char,int> mpci;
typedef map<string,int> mpsi;
typedef deque<int> deqi;
typedef deque<char> deqc;
typedef priority_queue<int> mxpq;
typedef priority_queue<int,vector<int>,greater<int> > mnpq;
typedef priority_queue<pii> mxpqii;
typedef priority_queue<pii,vector<pii>,greater<pii> > mnpqii;
const int maxn=500005;
const int inf=0x3f3f3f3f3f3f3f3f;
const int MOD=100000007;
const db eps=1e-10;
const db pi=3.1415926535;
int qpow(int a,int b){int tmp=a%MOD,ans=1;while(b){if(b&1){ans*=tmp,ans%=MOD;}tmp*=tmp,tmp%=MOD,b>>=1;}return ans;}
int lowbit(int x){return x&-x;}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
int mmax(int a,int b,int c){return max(a,max(b,c));}
int mmin(int a,int b,int c){return min(a,min(b,c));}
void mod(int &a){a+=MOD;a%=MOD;}
bool chk(int now){}
int half(int l,int r){while(l<=r){int m=(l+r)/2;if(chk(m))r=m-1;else l=m+1;}return l;}
int ll(int p){return p<<1;}
int rr(int p){return p<<1|1;}
int mm(int l,int r){return (l+r)/2;}
int lg(int x){if(x==0) return 1;return (int)log2(x)+1;}
bool smleql(db a,db b){if(a<b||fabs(a-b)<=eps)return true;return false;}
bool bigeql(db a,db b){if(a>b||fabs(a-b)<=eps)return true;return false;}
bool eql(db a,db b){if(fabs(a-b)<eps) return 1;return 0;}
db len(db a,db b,db c,db d){return sqrt((a-c)*(a-c)+(b-d)*(b-d));}
bool isp(int x){if(x==1)return false;if(x==2)return true;for(int i=2;i*i<=x;++i)if(x%i==0)return false;return true;}
inline int read(){
char ch=getchar();int s=0,w=1;
while(ch<48||ch>57){if(ch=='-')w=-1;ch=getchar();}
while(ch>=48&&ch<=57){s=(s<<1)+(s<<3)+ch-48;ch=getchar();}
return s*w;
}
inline void write(int x){
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+48);
}
int gcd(int a, int b){
if(a==0) return b;
if(b==0) return a;
if(!(a&1)&&!(b&1)) return gcd(a>>1,b>>1)<<1;
else if(!(b&1)) return gcd(a,b>>1);
else if(!(a&1)) return gcd(a>>1,b);
else return gcd(abs(a-b),min(a,b));
}
int lcm(int x,int y){return x*y/gcd(x,y);}
int n,m,_;
string s;
bitset<1005> bs[1005],A,B;
signed main(){
ios_base::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
re(i,1,n){
cin>>s;
re(j,0,m-1)
bs[i][j]=(s[j]=='1');
}
cin>>_;
while(_--){
cin>>s;
re(i,0,m-1){
if(s[i]=='1') A[i]=1,B[i]=1;
else if(s[i]=='0') A[i]=1,B[i]=0;
else A[i]=B[i]=0;
}
int cnt=0;
re(i,1,n){
if((A&bs[i])==B) cnt++;
}
cout<<cnt<<endl;
}
return 0;
}
E、
首先把异或前缀和预处理出来,注意数组全部都得右移一位,因为要把首位的\(0\)空出来
实际上题目要维护的是某个区间内两个最近的相同数字,考虑把询问按照右端点排序
由于值域较小,我们保存每个数字上一次出现的位置,并且单点更新那一点的最小值
最后区间询问最小值即可
注意\(0\)很特别,它第一次的出现位置应该在\(1\),所以在上面才把数组右移一位
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=500005;
int n,Q;
struct node{
int l,r,id;
}q[maxn];
int a[maxn],last[maxn*4],mn[maxn*4],ans[maxn];
bool cmp(node a,node b){
if(a.r!=b.r) return a.r<b.r;
else return a.l<b.l;
}
int ask(int L,int R,int p=1,int l=1,int r=n){
if(L<=l&&r<=R){
return mn[p];
}
int m=(l+r)/2;
int ret=0x3f3f3f3f;
if(L<=m) ret=min(ret,ask(L,R,p*2,l,m));
if(R>m) ret=min(ret,ask(L,R,p*2+1,m+1,r));
return ret;
}
void modi(int pos,int val,int p=1,int l=1,int r=n){
// cout<<"NMSL"<<endl;
if(l==r&&l==pos){
mn[p]=val;
// cout<<"??? "<<l<<' '<<val<<endl;
return;
}
int m=(l+r)/2;
if(pos<=m) modi(pos,val,p*2,l,m);
else modi(pos,val,p*2+1,m+1,r);
mn[p]=min(mn[p*2],mn[p*2+1]);
}
int main(){
scanf("%d%d",&n,&Q);
n++;
for(int i=2;i<=n;++i) scanf("%d",&a[i]);
a[1]=0;
for(int i=2;i<=n;++i) a[i]^=a[i-1];
for(int i=1;i<=Q;++i) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
sort(q+1,q+1+Q,cmp);
memset(mn,0x3f,sizeof(mn));
last[0]=1;
int flag=2;
for(int i=1;i<=Q;++i){
while(flag<=q[i].r+1){
int v=flag-last[a[flag]];
// printf("QAQ %d %d %d\n",flag,a[flag],last[a[flag]]);
if(last[a[flag]]!=0) modi(last[a[flag]],v);
last[a[flag]]=flag;
flag++;
}
// printf("! %d %d\n",q[i].l,q[i].r+1);
ans[q[i].id]=ask(q[i].l,q[i].r+1);
}
for(int i=1;i<=Q;++i) printf("%d\n",(ans[i]==0x3f3f3f3f)?-1:ans[i]);
return 0;
}
/*
5 3
1 2 3 4 5
1 5
1 1
1 3
*/