oneman233

牛客练习赛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
*/

posted on 2019-10-12 12:10  oneman233  阅读(139)  评论(0编辑  收藏  举报

导航