AtCoder Grand Contest 015

A - A+…+B Problem

模拟题意

#include<bits/stdc++.h>
using namespace std;

int n,a,b;

int main(){
	scanf("%d %d %d",&n,&a,&b);
	if(a==b  || a<b && n>=2) printf("%lld\n",1ll*(n-2)*(b-a)+1);
	else printf("0\n");
}

B - Evilator

模拟题意

#include<bits/stdc++.h>
using namespace std;

const int N=100010;
char s[N];
int n;

int main(){
	scanf("%s",s+1);n=strlen(s+1);
	long long tot=0;
	for(int i=1;i<=n;i++) 
		if(s[i]=='U') tot+=n-1+i-1;
		else tot+=n-1+n-i;
	printf("%lld\n",tot);
}

C - Nuske vs Phantom Thnook

保证是树了,用二维前缀和维护点数,横向连边数,纵向连边数即可。

#include<bits/stdc++.h>
using namespace std;

const int N=2010;
int n,m,q,h[N][N],l[N][N],sum[N][N];
char s[N][N];


int main(){
	scanf("%d %d %d",&n,&m,&q);
	for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) {
			sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
			if(s[i][j]=='1') sum[i][j]++;
		}
	for(int i=1;i<=n;i++)
		for(int j=1;j<m;j++) {
			h[i][j]=h[i-1][j]+h[i][j-1]-h[i-1][j-1];
			if(s[i][j]=='1' && s[i][j+1]=='1') h[i][j]++;
		}
	for(int i=1;i<n;i++)
		for(int j=1;j<=m;j++) {
			l[i][j]=l[i-1][j]+l[i][j-1]-l[i-1][j-1];
			if(s[i][j]=='1' && s[i+1][j]=='1') l[i][j]++; 
		}
	int x1,y1,x2,y2;
	while(q--){
		scanf("%d %d %d %d",&x1,&y1,&x2,&y2);x1--;y1--;
		printf("%d\n",sum[x2][y2]+sum[x1][y1]-sum[x1][y2]-sum[x2][y1]-
					  (h[x2][y2-1]+h[x1][y1]-h[x1][y2-1]-h[x2][y1])-
					  (l[x2-1][y2]+l[x1][y1]-l[x2-1][y1]-l[x1][y2]));
	}
}

D - A or…or B Problem

考虑不相同的最高位为 p p p,即 t = 2 p t=2^p t=2p,忽略 A , B > p A,B>p A,B>p的位置。
[ A , t ) [A,t) [A,t)自己或,会生成 [ A , t ) [A,t) [A,t)
[ t , B ] [t,B] [t,B]自己或,会生成 [ t , 2 p o s + 1 ) [t,2^{pos+1}) [t,2pos+1) p o s pos pos B B B p p p外的最高有 1 1 1位置。
用两个一起或,会生成 [ t + A , 2 t ) [t+A,2t) [t+A,2t)
注意后面两个可能有交,答案三者加起来即可。

#include<bits/stdc++.h>
using namespace std;

long long a,b;

int main(){
	scanf("%lld %lld",&a,&b);
	int pos=59;
	while(pos!=-1 && ((a>>pos)&1)==((b>>pos)&1)) pos--;
	if(pos==-1) printf("1\n");
	else if(pos==0) printf("2\n");
	else{
		long long tot=(1ll<<pos);
		a&=tot-1;b&=tot-1;
		long long ans=tot-a;pos--;
		while(pos!=-1 && ((b>>pos)&1)==0) pos--;
		ans+=min((1ll<<(pos+1))+tot-a,tot);
		printf("%lld\n",ans);
	}
}

E - Mr.Aoki Incubator

现将位置和速度都离散化,速度的大小关系恰好是 + inf ⁡ +\inf +inf时间两两的位置关系。
可以发现,一个点可以覆盖的点是一个以速度大小为下标的区间。
即,位置比当前小且速度最大的点,一定会被覆盖,位置比当前大且速度最小的点,也一定会被覆盖。
两者中间的点要么会自己经过当前点,要么会被这两个点(可能是其中之一)经过。
仔细讨论又会发现:将区间按照对应点的原来位置排序后,左端点右端点都满足不降序。
貌似求两个端点可以直接对于位置顺序遍历搞定,但是博主比较蠢按照速度遍历还写了个树状数组。
读者自证不难。
那么直接前缀和优化 D p Dp Dp即可。

#include<bits/stdc++.h>
using namespace std;

const int N=200010,mod=1000000007;
int n,x[N],v[N],p[N],sum[N],L[N],R[N],a[N],pre[N];
vector<int> V[N];

void add(int x,int t){
	while(x<=n){
		sum[x]=min(sum[x],t);
		x+=(x&(-x));
	}
}

int gs(int x){
	int tot=1e9;
	while(x){
		tot=min(tot,sum[x]);
		x-=(x&(-x));
	}
	return tot;
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d %d",&x[i],&v[i]);
	for(int i=1;i<=n;i++) p[i]=x[i];sort(p+1,p+1+n);
	for(int i=1;i<=n;i++) x[i]=lower_bound(p+1,p+1+n,x[i])-p;
	for(int i=1;i<=n;i++) p[i]=v[i];sort(p+1,p+1+n);
	for(int i=1;i<=n;i++) v[i]=lower_bound(p+1,p+1+n,v[i])-p,a[v[i]]=x[i];
	for(int i=1;i<=n;i++) sum[i]=1e9;
	for(int i=1;i<=n;i++){
		add(n-a[i]+1,i);
		L[i]=gs(n-a[i]+1);
	}
	for(int i=1;i<=n;i++) sum[i]=1e9;
	for(int i=n;i>=1;i--){
		add(a[i],n-i+1);
		R[i]=n-gs(a[i])+1;
		V[R[i]].push_back(L[i]);
	}
	pre[0]=1;
	for(int i=1;i<=n;i++){
		pre[i]=pre[i-1];
		sort(V[i].begin(),V[i].end());
		for(int j=0;j<V[i].size();j++)
			pre[i]=(2ll*pre[i]+mod-(V[i][j]==1?0:pre[V[i][j]-2]))%mod;
	}
	printf("%d\n",(pre[n]+mod-pre[n-1])%mod);
}

F - Kenus the Ancient Greek

这种构造结论题应该不是人想的。
首先显然 ( F [ i ] , F [ i + 1 ] ) = i − 1 (F[i],F[i+1])=i-1 (F[i],F[i+1])=i1
定义优秀的数对为 ( x , y ) = k (x,y)=k (x,y)=k,当且仅当 x , y ≤ 2 ∗ F [ k + 2 ] x,y\leq2*F[k+2] x,y2F[k+2]
定义好的数对为 ( x , y ) = k (x,y)=k (x,y)=k,当且仅当不存在 x ′ , y ′ < x , y x',y'<x,y x,y<x,y ( x ′ , y ′ ) > k (x',y')>k (x,y)>k
可以发现优秀的数对 ( x , y ) = k (x,y)=k (x,y)=k的个数不超过 O ( k ) O(k) O(k)个。
显然要求的所有数对都是好的数对。
如何建立起两者的联系?
定理:一个好的数对经过一次变换之后会变成一个优秀的数对。
如果知道了这件事情,我们就可以暴力枚举值为 a n s − 1 ans-1 ans1的优秀的数对,计算出值为 a n s ans ans的好的数对个数。
如何证明?考虑反证法,推出不满足好的数对性质的矛盾即可。

#include<bits/stdc++.h>
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define LL long long
#define mod 1000000007
using namespace std;

const int N=110;
int T;
LL f[N];
vector<pair<LL,LL> > p[N];

int main(){
	f[0]=0;f[1]=1;
	int t=-1;
	for(int i=0;f[i+1]<=1e18;i++) t++,f[i+2]=f[i]+f[i+1];
	p[1].pb(mk(1,2));p[1].pb(mk(1,3));p[1].pb(mk(1,4));
	for(int i=2;i<=t;i++){
		for(int j=0;j<p[i-1].size();j++){
			LL a=p[i-1][j].se,b=p[i-1][j].fi+p[i-1][j].se;
			p[i].pb(mk(a,b));
			while(a+b<=2*f[i+2]) b+=a,p[i].pb(mk(a,b));
		}
	}
	LL x,y;
	scanf("%d",&T);
	while(T--){
		scanf("%lld %lld",&x,&y);
		if(x>y) swap(x,y);
		int ans=1;
		while(x>=f[ans+2] && y>=f[ans+3]) ans++;
		printf("%d ",ans);
		if(ans==1) printf("%lld\n",1ll*x*y%mod);
		else{
			ans--;
			LL tot=0;
			for(int i=0;i<p[ans].size();i++){
				if(p[ans][i].se>x) continue;
				if(p[ans][i].fi<=y) tot+=(y-p[ans][i].fi)/p[ans][i].se;
				if(p[ans][i].fi<=x) tot+=(x-p[ans][i].fi)/p[ans][i].se;
				tot%=mod;
			}
			printf("%lld\n",tot);
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值