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;
}

  

时间: 2024-08-06 20:07:10

XVII Open Cup named after E.V. Pankratiev. Eastern GP, Division 1的相关文章

XVII Open Cup named after E.V. Pankratiev. Grand Prix of America (NAIPC-2017)

A. Pieces of Parentheses 将括号串排序,先处理会使左括号数增加的串,这里面先处理减少的值少的串:再处理会使左括号数减少的串,这里面先处理差值较大的串.确定顺序之后就可以DP了. 时间复杂度$O(n^3)$. #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=310,inf=1000000; int n,i,j,m,all,

XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem A. Arithmetic Derivative

题目:Problem A. Arithmetic DerivativeInput file: standard inputOutput file: standard inputTime limit: 1 secondMemory limit: 256 mebibytesLets define an arithmetic derivative:? if p = 1 then p0 = 0;? if p is prime then p0 = 1;? if p is not prime then n0

XVII Open Cup named after E.V. Pankratiev. GP of SPb

A. Array Factory 将下标按前缀和排序,然后双指针,维护最大的右边界即可. #include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int N=200010; int n,i,j,anslen,ansl,ansr,mr,q[N]; ll a[N],lim; inline bool cmp(int x,int y){return a[x]<a[y];

【二分】【字符串哈希】【二分图最大匹配】【最大流】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem I. Minimum Prefix

给你n个字符串,问你最小的长度的前缀,使得每个字符串任意循环滑动之后,这些前缀都两两不同. 二分答案mid之后,将每个字符串长度为mid的循环子串都哈希出来,相当于对每个字符串,找一个与其他字符串所选定的子串不同的子串,是个二分图最大匹配的模型,可以匈牙利或者Dinic跑最大流看是否满流. 一个小优化是对于某个字符串,如果其所有不同的子串数量超过n,那么一定满足,可以直接删去. 卡常数,不能用set,map啥的,采取了用数组记录哈希值,排序后二分的手段进行去重和离散化. #include<cst

XVII Open Cup named after E.V. Pankratiev. GP of Two Capitals

A. Artifact Guarding 选出的守卫需要满足$\max(a+b)\leq \sum a$,从小到大枚举每个值作为$\max(a+b)$,在权值线段树上找到最大的若干个$a$即可. 时间复杂度$O(n\log n)$. #include<cstdio> #include<algorithm> #include<set> #include<map> using namespace std; typedef long long ll; const

XVII Open Cup named after E.V. Pankratiev. XXI Ural Championship

A. Apple 按题意模拟即可. #include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include

XVII Open Cup named after E.V. Pankratiev Grand Prix of Moscow Workshops, Sunday, April 23, 2017 Problem D. Great Again

题目: Problem D. Great AgainInput file: standard inputOutput file: standard outputTime limit: 2 secondsMemory limit: 512 megabytesThe election in Berland is coming. The party United Berland is going to use its influence to win themagain. The crucial co

XVII Open Cup named after E.V. Pankratiev Grand Prix of Moscow Workshops, Sunday, April 23, 2017 Problem K. Piecemaking

题目:Problem K. PiecemakingInput file: standard inputOutput file: standard outputTime limit: 1 secondMemory limit: 512 mebibytesThe civil war in Berland continues for five years already. The United Nation decided to end the bloodshed.Berland consists o

【枚举】XVII Open Cup named after E.V. Pankratiev Stage 4: Grand Prix of SPb, Sunday, Octorber 9, 2016 Problem D. Cutting Potatoes

题意:有n个土豆,每个有体积V(i),你可以将每个土豆等分为不超过K份,问你最大块和最小块比值最小为多少. 直接枚举切法,只有n*K种,然后保证其为最大块,去算其他块的切法,即让其他块切得尽可能大即可.O(n*n*K). #include<cstdio> #include<cstring> using namespace std; int n,K,a[105],ans1=150,ans2=1,x[105],ansx[105]; int main(){ // freopen(&quo