XVII Open Cup named after E.V. Pankratiev. Eastern GP, Division 1

A. Count The Ones

$ans=b-c+1$。

#include <stdio.h>
using namespace std ;

int a  , b , c ;

void solve () {
	printf ( "%d\n" , 1 + b - c ) ;
}

int main () {
	while ( ~scanf ( "%d%d%d" , &a , &b , &c ) ) solve () ;
	return 0 ;
}

  

B. Craters

求出凸包,然后枚举凸包上两个点,对第三个点旋转卡壳。因为随机数据凸包期望点数为$O(\sqrt{n})$,故时间复杂度为$O(n\log n)$。

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<int,int>PI;
const int N=200010;
int n,m,_,i,j,k,x,y;
set<PI>T;
ll ans=-1;
struct P{
  int x,y;
  P(){}
  P(int _x,int _y){x=_x,y=_y;}
  P operator-(P b){return P(x-b.x,y-b.y);}
  bool operator<(const P&p)const{
    if(x!=p.x)return x<p.x;
    return y<p.y;
  }
  void write(){
    printf("%d %d\n",x,y);
  }
}a[N],b[N<<1],ans0,ans1,ans2;
inline ll cross(P a,P b){
  return 1LL*a.x*b.y-1LL*a.y*b.x;
}
inline ll vect(P p,P p1,P p2){
  return 1LL*(p1.x-p.x)*(p2.y-p.y)-1LL*(p1.y-p.y)*(p2.x-p.x);
}
int convexhull(P*p,int n,P*q){
  int i,k,m;
  sort(p,p+n);
  m=0;
  for(i=0;i<n;q[m++]=p[i++])while(m>1&&vect(q[m-2],q[m-1],p[i])<=0)m--;
  k=m;
  for(i=n-2;i>=0;q[m++]=p[i--])while(m>k&&vect(q[m-2],q[m-1],p[i])<=0)m--;
  return --m;
}
inline void work(P a,P b,P c){
  ll now=cross(a,b)+cross(b,c)+cross(c,a);
  if(now<0)now=-now;
  if(now>ans)ans=now,ans0=a,ans1=b,ans2=c;
}
inline ll area(P a,P b,P c){
  ll now=cross(a,b)+cross(b,c)+cross(c,a);
  if(now<0)now=-now;
  return now;
}
int main(){
  scanf("%d",&n);
  if(n<200){
    for(i=0;i<n;i++)scanf("%d%d",&a[i].x,&a[i].y);
    for(i=0;i<n;i++)for(j=0;j<i;j++)for(k=0;k<j;k++){
      work(a[i],a[j],a[k]);
    }
    ans0.write();
    ans1.write();
    ans2.write();
    return 0;
  }
  _=n;
  n=0;
  while(_--){
    scanf("%d%d",&x,&y);
    if(T.find(PI(x,y))!=T.end())continue;
    a[n++]=P(x,y);
    T.insert(PI(x,y));
  }
  m=convexhull(a,n,b);
  for(i=0;i<m;i++)b[i+m]=b[i];
  for(i=0;i<m;i++){
    for(j=i+1,k=j+1;j<i+m;j++){
      if(k<=j)k=j+1;
      while(k+1<i+m&&area(b[i],b[j],b[k])<=area(b[i],b[j],b[k+1]))k++;
      work(b[i],b[j],b[k]);
    }
  }
  ans0.write();
  ans1.write();
  ans2.write();
}

  

C. MSTrikes back!

记录最后$5$个点连通性的最小表示然后DP,注意到边权的周期不会太大,所以可以直接跳过完整的周期。

#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<time.h>
#include<assert.h>
#include<iostream>
using namespace std;
typedef long long LL;
typedef pair<int,int>pi;
const int Ms=3125;
const LL Inf=1LL<<60;
const int LIM=100;
int n,seed;
LL in[LIM+1];
LL f[LIM+1][Ms];
LL dp[2][Ms];
void init(int cs,LL val){
	for(int i=0;i<Ms;i++)dp[cs][i]=val;
}
int g[Ms][(1<<5)+1];
void decode(int mask,int *a){
	for(int i=0;i<5;i++){
		a[i]=mask%5;
		mask/=5;
	}
}
void zuixiao(int *a){
	int dui[10];
	memset(dui,-1,sizeof dui);
	int cur=0;
	for(int i=0;i<5;i++){
		int x=a[i];
		if(dui[x]<0){
			dui[x]=cur++;
		}
		a[i]=dui[x];
	}
}
int encode(int *a){
	int res=0,tmp=1;
	for(int i=0;i<5;i++,tmp=tmp*5){
		res+=a[i]*tmp;
	}
	return res;
}
bool testt(int *a){
	int b[10];
	for(int i=0;i<5;i++)b[i]=a[i];
	zuixiao(b);
	for(int i=0;i<5;i++)if(b[i]!=a[i])return 0;
	return 1;
}
void pre(){
	int a[10],b[10];
	for(int mask=0;mask<Ms;mask++){
		decode(mask,a);
		if(!testt(a)){
			for(int j=0;j<1<<5;j++)g[mask][j]=-1;
			continue;
		}
		//for(int i=0;i<5;i++)printf("%d ",a[i]);puts(":\n");
		for(int j=0;j<1<<5;j++){
			for(int i=0;i<5;i++)b[i]=a[i];
			b[5]=6;
			for(int k=0;k<5;k++){
				if(j>>k&1){
					for(int t=0;t<5;t++){
						if(t==k)continue;
						if(b[t]==b[k])b[t]=b[5];
					}
					b[k]=b[5];
				}
			}
			bool flag=0;
			for(int k=1;k<=5;k++)if(b[0]==b[k]){flag=1;break;}
			if(!flag)g[mask][j]=-1;
			else{
				for(int k=0;k<5;k++)b[k]=b[k+1];
				zuixiao(b);
				//for(int k=0;k<5;k++)printf("%d ",b[k]);puts("");
				g[mask][j]=encode(b);
			}
		}
	}
}
void upd(LL &x,LL y){if(x>y)x=y;}
int main(){
	pre();
	int _;scanf("%d",&_);
	while(_--){
		scanf("%d%d",&n,&seed);
		int cs=0;
		init(cs,Inf);
		dp[cs][0]=0;
		for(int i=2;i<=n&&i<=LIM;i++){
			init(cs^1,Inf);
			seed=seed*907%2333333;
			LL bq[10];
			int T=seed;
			in[i]=T;
			for(int j=0;j<5;j++){
				if(i-(5-j)<1)bq[j]=Inf;
				else {
					seed=seed*907%2333333;
					bq[j]=seed^T;
				}
			}
			for(int mask=0;mask<Ms;mask++){
				LL w=dp[cs][mask];
				if(w==Inf)continue;
				for(int j=0;j<1<<5;j++){
					if(g[mask][j]<0)continue;
					bool flag=1;
					for(int k=0;k<5;k++)if((j>>k&1)&&(bq[k]==Inf)){
						flag=0;continue;
					}
					if(!flag)continue;
					LL nw=w;
					for(int k=0;k<5;k++){
						if(j>>k&1)nw+=bq[k];
					}
					upd(dp[cs^1][g[mask][j]],nw);
				}
			}
			cs^=1;
			for(int j=0;j<Ms;j++)f[i][j]=dp[cs][j];
		}
		if(n<=LIM)printf("%lld\n",dp[cs][0]);
		else{
			LL pace,pacew;
			for(int i=LIM-1;;i--)if(in[i]==in[LIM]){
				pace=LIM-i;
				break;
			}
			int st=(n-LIM)/pace*pace+LIM;
			//printf("st=%d\n",st);
			for(int i=0;i<Ms;i++){
				dp[cs][i]=f[LIM][i]+1LL*(n-LIM)/pace*(f[LIM][i]-f[LIM-pace][i]);
			}
			for(int i=st+1;i<=n;i++){
				init(cs^1,Inf);
				seed=seed*907%2333333;
				LL bq[10];
				int T=seed;
				for(int j=0;j<5;j++){
					if(i-(5-j)<1)bq[j]=Inf;
					else {
						seed=seed*907%2333333;
						bq[j]=seed^T;
					}
				}
				for(int mask=0;mask<Ms;mask++){
					LL w=dp[cs][mask];
					if(w==Inf)continue;
					for(int j=0;j<1<<5;j++){
						if(g[mask][j]<0)continue;
						bool flag=1;
						for(int k=0;k<5;k++)if((j>>k&1)&&(bq[k]==Inf)){
							flag=0;continue;
						}
						if(!flag)continue;
						LL nw=w;
						for(int k=0;k<5;k++){
							if(j>>k&1)nw+=bq[k];
						}
						upd(dp[cs^1][g[mask][j]],nw);
					}
				}
				cs^=1;
			}
			printf("%lld\n",dp[cs][0]);
		}
	}	
	return 0;
}

  

D. Skyscrapers

首先用set维护所有已经被摧毁的建筑。然后用线段树维护区间内最容易被向左/向右的冲击波击毁的建筑即可。时间复杂度$O(n\log n)$。

#include<cstdio>
#include<set>
#include<algorithm>
using namespace std;
const int N=100010,M=262150;
int n,m,i,x,ans,f[N],g[N];
set<int>T;
int vl[M],vr[M],pos[N],p;
inline int mergel(int x,int y){
  if(!x||!y)return x+y;
  return f[x]>f[y]?x:y;
}
inline int merger(int x,int y){
  if(!x||!y)return x+y;
  return g[x]<g[y]?x:y;
}
void build(int x,int a,int b){
  if(a==b){
    pos[a]=x;
    vl[x]=vr[x]=a;
    return;
  }
  int mid=(a+b)>>1;
  build(x<<1,a,mid);
  build(x<<1|1,mid+1,b);
  vl[x]=mergel(vl[x<<1],vl[x<<1|1]);
  vr[x]=merger(vr[x<<1],vr[x<<1|1]);
}
void askl(int x,int a,int b,int c,int d){
  if(c<=a&&b<=d){
    p=mergel(p,vl[x]);
    return;
  }
  int mid=(a+b)>>1;
  if(c<=mid)askl(x<<1,a,mid,c,d);
  if(d>mid)askl(x<<1|1,mid+1,b,c,d);
}
void askr(int x,int a,int b,int c,int d){
  if(c<=a&&b<=d){
    p=merger(p,vr[x]);
    return;
  }
  int mid=(a+b)>>1;
  if(c<=mid)askr(x<<1,a,mid,c,d);
  if(d>mid)askr(x<<1|1,mid+1,b,c,d);
}
inline void kill(int x){
  ans++;
  T.insert(x);
  x=pos[x];
  vl[x]=vr[x]=0;
  for(x>>=1;x;x>>=1){
    vl[x]=mergel(vl[x<<1],vl[x<<1|1]);
    vr[x]=merger(vr[x<<1],vr[x<<1|1]);
  }
}
inline void workl(int l,int r,int t){
  if(l>r)return;
  while(1){
    p=0;
    askl(1,1,n,l,r);
    if(!p)return;
    if(f[p]<t)return;
    kill(p);
  }
}
inline void workr(int l,int r,int t){
  if(l>r)return;
  while(1){
    p=0;
    askr(1,1,n,l,r);
    if(!p)return;
    if(g[p]>t)return;
    kill(p);
  }
}
int main(){
  scanf("%d",&n);
  for(i=1;i<=n;i++)scanf("%d",&x),f[i]=i-x,g[i]=i+x;
  T.insert(0);
  T.insert(n+1);
  build(1,1,n);
  scanf("%d",&m);
  while(m--){
    scanf("%d",&x);
    ans=0;
    kill(x);
    set<int>::iterator j=T.find(x),k;
    k=j;
    j--;k++;
    workl(*j+1,x-1,f[x]);
    workr(x+1,*k-1,g[x]);
    printf("%d\n",ans);
  }
/*
left:
a[x]-a[y]>=x-y
y-a[y]>=x-a[x]
get max(y-a[y])
right:
a[x]-a[y]>=y-x
y+a[y]<=x+a[x]
get min(y+a[y])
*/
}

  

E. Blackboard

按题意模拟即可。

#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<time.h>
#include<assert.h>
#include<iostream>
using namespace std;
typedef long long LL;
typedef pair<int,int>pi;
int n,ty;
int a[103][103];
void rev(){
	for(int i=1;i<=n;i++){
		for(int j=i;j<=n;j++){
			swap(a[i][j],a[j][i]);
		}
	}
}
void solve1(){
	int cur=1;
	for(int i=1;i<=n;i++){
		if(i&1){
			for(int j=1;j<=n;j++){
				a[i][j]=cur++;
			}
		}
		else{
			for(int j=n;j>=1;j--){
				a[i][j]=cur++;
			}
		}
	}
}
bool isok(int x,int y){
	return x>=1&&x<=n&&y>=1&&y<=n&&a[x][y]==0;
}
int di[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
void solve2(){
	int d=0;
	int sx=1,sy=1;
	memset(a,0,sizeof a);
	int cur=1;
	for(int it=1;it<=n*n;it++){
		a[sx][sy]=cur++;
		int nx=sx+di[d][0],ny=sy+di[d][1];
		if(it==n*n)break;
		while(!isok(nx,ny)){
			d++;
			d%=4;
			nx=sx+di[d][0],ny=sy+di[d][1];
		}
		sx=nx,sy=ny;
	}
}
int main(){
	while(scanf("%d%d",&n,&ty)!=EOF){
		if(ty==1||ty==2)solve1();
		if(ty==3||ty==4)solve2();
		if(ty==2||ty==4)rev();
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				printf("%d%c",a[i][j],j==n?'\n':' ');
			}
		}
	}
	return 0;
}

  

F. Buddy Numbers

若质数太多那么显然无解,对于小数据爆搜即可。

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

int a[1000] , n ;

void solve () {
	if ( n == 1 ) {
		printf ( "1\n" ) ;
		return ;
	}
	if ( n == 2 ) {
		printf ( "1 2\n" ) ;
		return ;
	}
	if ( n == 3 ) {
		printf ( "2 1 3\n" ) ;
		return ;
	}
	if ( n == 4 ) {
		printf ( "2 4 1 3\n" ) ;
		return ;
	}
	if ( n == 6 ) {
		printf ( "3 6 2 4 1 5\n" ) ;
		return ;
	}
	printf ( "-1\n" ) ;
		
}

int main () {
	while ( ~scanf ( "%d" , &n ) ) solve () ;
	return 0 ;
}

  

G. Gmoogle

按题意模拟即可。注意首尾空格的处理以及文末没有标点符号的情况的处理。

#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<time.h>
#include<assert.h>
#include<sstream>
#include<iostream>
using namespace std;
typedef long long LL;
typedef pair<int,int>pi;
string s;
vector<string>jz;
int can[1020];
int isend(int loc){
	if(s[loc]!='.'&&s[loc]!='!'&&s[loc]!='?')return 0;
	if(s[loc]=='.'){
		int j=loc+1;
		while(j<s.size()&&s[j]==' ')j++;
		if(j<s.size()&&s[j]>='a'&&s[j]<='z')return 0;
	}
	return 1;
}
void cg(char &c){if(c>='A'&&c<='Z')c=c-'A'+'a';}
bool cmp(char c1,char c2){
	cg(c1),cg(c2);
	if(c1==c2)return 1;
	return 0;
}
bool ok(string &wb,string& in){
	for(int i=0;i+in.size()<=wb.size();i++)if(isalpha(wb[i])){
		bool flag=1;
		if(i&&isalpha(wb[i-1]))continue;//
		int j=i+in.size();
		if(j<wb.size()&&isalpha(wb[j]))continue;//
		//while ( j < wb.size () && wb[j] == ' ' ) ++ j ;
		//if(j<wb.size()-1&&wb[j]=='.')continue;
		for(int j=0;j<in.size();j++){
			if(cmp(wb[i+j],in[j])!=1){flag=0;break;}
		}
		if(flag)return 1;
	}
	return 0;
}
bool zhu(char x){
  if(x>='a'&&x<='z')return 1;
  if(x>='A'&&x<='Z')return 1;
  if(x==' ')return 1;
  if(x>='0'&&x<='9')return 1;
  if(x=='.'||x=='?'||x=='!')return 1;
  return 0;
}
void fix ( string& s ) {
	while ( !zhu(s[s.size () - 1]) ) s.pop_back () ;
}
int main(){
	getline(cin,s);
	fix ( s ) ;
	int k = 0 ;
	for(int l=0;l<s.size();){
		while(l<s.size()&&s[l]==' ')l++;
		if(l>=s.size())break;
		//if ( s[l] == '.' /*|| s[l] == '?' || s[k] == '!'*/ ) while ( 1 ) ;
		int r=l;
		string tmp="";
		while(r<s.size()&&!isend(r))tmp.push_back(s[r++]);
		if ( r < s.size () ) tmp.push_back(s[r++]);
		while(tmp[tmp.size()-1]==' ')tmp.pop_back();
		//printf ( "%d\n" , ( int ) tmp.size () ) ;
		jz.push_back(tmp);
		l=r;
	}
	/*
	cout<<"OUTPUT"<<endl;
	for(int i=0;i<jz.size();i++)cout<<jz[i]<<endl;
	*/
	int q;scanf("%d",&q);
	string rub;
	getline(cin,rub);
	while(q--){
		string que;
		getline(cin,que);
		fix ( que ) ;
		for(int i=0;i<jz.size();i++)can[i]=1;
		stringstream ss(que);
		string tmp;
		while(ss>>tmp){
			fix ( tmp ) ;
			for(int i=0;i<jz.size();i++){
				if(!ok(jz[i],tmp))can[i]=0;
			}
		}
		int i=0,j=que.size()-1;
		while(que[i]==' ')i++;
		while(que[j]==' ')j--;
		cout<<"Search results for \"";
		for(int it=i;it<=j;it++)printf("%c",que[it]);
		cout<<"\":\n";
		for(int i=0;i<jz.size();i++)if(can[i]){
			cout<<"- \""<<jz[i]<<"\"\n";
		}
	}
	return 0;
}

  

H. Generator

线性筛求出每个数的最小质因子即可。

#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<time.h>
#include<assert.h>
#include<iostream>
using namespace std;
typedef long long LL;
typedef pair<int,int>pi;
LL n;
LL sum[10000020];
int tot[10000020];
bool isp[10000200];
vector<int>pri;
const int Maxn=10000010;
int getsq(int x){
	int tmp=sqrt(x+0.5);
	while(tmp*tmp<x)tmp++;
	while(tmp*tmp>x)tmp--;
	return tmp-1;
}
void pre(){
	for(int i=2;i<Maxn;i++){
		if(!isp[i])pri.push_back(i),sum[i]=getsq(i);
		for(int j=0;j<pri.size();j++){
			int x=pri[j];
			if(x*i>=Maxn)break;
			sum[x*i]=x-1;
			isp[i*x]=1;
			if(i%x==0)break;
		}
	}
	//for(int i=2;i<=10;i++)printf("%lld ",sum[i]);puts("");
	for(int i=2;i<Maxn;i++)sum[i]+=sum[i-1];
	for(int i=2;i<Maxn;i++)tot[i]=tot[i-1]+(!isp[i]);
}
int main(){
	pre();
	int _;scanf("%d",&_);
	while(_--){
		scanf("%lld",&n);
		LL ans=sum[n];
		if(ans==0)printf("0/1\n");
		else{
			LL gc=__gcd((LL)tot[n],ans);
			printf("%lld/%lld\n",ans/gc,tot[n]/gc);
		}		
	}
	return 0;
}

  

I. Addition

维护二进制字典树即可。

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

typedef long long LL ;

const int MAXN = 100005 ;

int nxt[MAXN][2] ;
int cnt[MAXN] ;
char s[MAXN] , s1[MAXN] ;
int cur , root ;
int n , m ;

int newnode () {
	++ cur ;
	nxt[cur][0] = nxt[cur][1] = 0 ;
	cnt[cur] = 0 ;
	return cur ;
}

void insert ( char s[] ) {
	int now = root ;
	for ( int i = 0 ; i < m ; ++ i ) {
		int x = s[i] ;
		if ( !nxt[now][x] ) nxt[now][x] = newnode () ;
		now = nxt[now][x] ;
		cnt[now] ++ ;
	}
}

int query ( char s[] ) {
	int now = root , ans = 0 ;
	for ( int i = 0 ; i < m ; ++ i ) {
		int x = s[i] ;
		if ( !x ) ans += cnt[nxt[now][1]] ;
		now = nxt[now][x] ;
	}
	return ans ;
}

void solve () {
	cur = 0 ;
	root = newnode () ;
	for ( int i = 1 ; i <= n ; ++ i ) {
		scanf ( "%s" , s ) ;
		for ( int j = 0 ; j < m ; ++ j ) {
			s[j] -= '0' ;
			s1[j] = 1 ^ s[j] ;
		}
		int ans = query ( s1 ) ;
		insert ( s ) ;
		printf ( "%d\n" , ans ) ;
		fflush ( stdout ) ;
	}
}

int main () {
	scanf ( "%d%d" , &n , &m ) ;
	solve () ;
	return 0 ;
}

  

J. Votter and Paul De Mort

留坑。

 

K. GCD on the segments

考虑枚举左端点$i$,则随着右端点的右移,一共只有$O(\log n)$种不同的$\gcd$取值。所以首先通过ST表+二分查找预处理出$O(n\log n)$个四元组$(x,i,l,r)$,表示左端点为$i$,右端点取值范围在$[l,r]$内,且这一段的$\gcd$都为$x$。

将四元组按照$x$为第一关键字,$i$为第二关键字排序,对于相同的$x$一起处理。

当$x$相同时,显然所有的$i$互不相同。设$f[i]$为恰好以位置$i$为结尾的最优解,则对于一个四元组$(x,i,l,r)$,能更新它的最优解为区间$[1,i-1]$的最优值$+1$,然后用它更新区间$[l,r]$的$f[]$。用支持打标记的线段树维护即可。时间复杂度$O(n\log^2n)$。

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int N=100010,K=17,P=1000000007,M=262145;
int T,n,m,i,j,x,y,l,r,mid,Log[N],val,f[K][N];
struct PI{
  int x,i,l,r;
  PI(){}
  PI(int _x,int _i,int _l,int _r){x=_x,i=_i,l=_l,r=_r;}
}a[3000000];
inline bool cmp(PI a,PI b){return a.x==b.x?a.i<b.i:a.x<b.x;}
struct Num{
  int x,y;
  Num(){x=y=0;}
  Num(int _x,int _y){x=_x,y=_y;}
  inline Num operator+(Num b){
    if(x<b.x)return b;
    if(x>b.x)return Num(x,y);
    return Num(x,(y+b.y)%P);
  }
  inline Num operator+(int _x){return Num(x+_x,y);}
  inline Num operator-(int b){return Num(x,(long long)y*b%P);}
  inline void operator+=(Num b){*this=*this+b;}
}tmp,v[M],tag[M],ans;
int pos[M];
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10LL)+=c-'0';}
inline int askgcd(int y){int k=Log[y-i+1];return __gcd(f[k][i],f[k][y-(1<<k)+1]);}
inline void clean(int x){
  if(pos[x]<T)pos[x]=T,v[x]=tag[x]=Num();
}
inline void tag1(int x,Num y){
  clean(x);
  v[x]+=y;
  tag[x]+=y;
}
inline void pb(int x){
  if(tag[x].x){
    tag1(x<<1,tag[x]);
    tag1(x<<1|1,tag[x]);
    tag[x]=Num();
  }
}
inline void up(int x){
  clean(x<<1),clean(x<<1|1);
  v[x]=v[x<<1]+v[x<<1|1];
}
void change(int x,int a,int b,int c,int d){
  clean(x);
  if(c<=a&&b<=d){tag1(x,tmp);return;}
  pb(x);
  int mid=(a+b)>>1;
  if(c<=mid)change(x<<1,a,mid,c,d);
  if(d>mid)change(x<<1|1,mid+1,b,c,d);
  up(x);
}
void ask(int x,int a,int b,int c,int d){
  clean(x);
  if(c<=a&&b<=d){tmp+=v[x];return;}
  pb(x);
  int mid=(a+b)>>1;
  if(c<=mid)ask(x<<1,a,mid,c,d);
  if(d>mid)ask(x<<1|1,mid+1,b,c,d);
  up(x);
}
int main(){
  for(i=2;i<=100000;i++)Log[i]=Log[i>>1]+1;
  while(~scanf("%d",&n)){
    m=0;
    ans=Num();
    for(i=1;i<=n;i++)read(f[0][i]);
    int flag=0;
    for(i=2;i<=n;i++)if(f[0][i]!=f[0][i-1]){flag=1;break;}
    if(!flag){printf("%d 1\n",n);continue;}
    for(j=1;j<K;j++)for(i=1;i+(1<<j-1)<=n;i++)f[j][i]=__gcd(f[j-1][i],f[j-1][i+(1<<j-1)]);
    for(i=1;i<=n;i++)for(x=i;x<=n;x=y+1){
      val=askgcd(y=x),l=x+1,r=n;
      while(l<=r)if(askgcd(mid=(l+r)>>1)==val)l=(y=mid)+1;else r=mid-1;
      a[++m]=PI(val,i,x,y);
    }
    sort(a+1,a+m+1,cmp);
    for(i=1;i<=m;i++){
      if(i==1||a[i].x!=a[i-1].x)T++;
      tmp=Num();
      if(a[i].i>1)ask(1,1,n,1,a[i].i-1);
      if(!tmp.x)tmp=Num(1,1);else tmp.x++;
      ans+=tmp-(a[i].r-a[i].l+1);
      change(1,1,n,a[i].l,a[i].r);
    }
    printf("%d %d\n",ans.x,ans.y);
  }
  return 0;
}

  

L. Fibonacci Equation

分类讨论。

#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<time.h>
#include<assert.h>
#include<iostream>
using namespace std;
typedef long long LL;
typedef pair<int,int>pi;
LL a[100];
LL x,y,z;
int main(){
	/*
	a[0]=0,a[1]=1;
	for(int i=2;i<=30;i++)a[i]=a[i-1]+a[i-2];
	for(int i=1;i<=25;i++){
		printf("%lld %lld\n",a[i],a[i]*a[i]-4*a[i-1]*a[i+1]);
	}
	*/
	while(scanf("%lld%lld%lld",&x,&y,&z)!=EOF){
		if(x==0){printf("1\n");continue;}
		if(y>x&&y>z){
			if(y==3)printf("1\n");
			else printf("2\n");
		}
		if(y<x&&y<z)printf("0\n");
		if(y>min(x,z)&&y<max(x,z)){
			if(y==1)printf("2\n");
			else printf("0\n");
		}
		//printf("real=%lld\n",a[y]*a[y]-4*a[x]*a[z]);
	}
	return 0;
}

  

posted @ 2017-03-30 23:37  Claris  阅读(439)  评论(0编辑  收藏  举报