ACM ICPC Vietnam National Second Round

A. Stock Market

枚举哪一天买入,哪一天卖出即可。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int P=1000000;
int T,n,i,a[111],j,ans,m;
int main(){
  scanf("%d",&T);
  while(T--){
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)scanf("%d",&a[i]);
    ans=0;
    for(i=1;i<=n;i++)for(j=i+1;j<=n;j++)if(a[i]<a[j]){
      ans=max(ans,(a[j]-a[i])*(m/a[i]));
    }
    printf("%d\n",ans);
  }
  return 0;
}

  

B. Sum

经典分段计算。时间复杂度$O(\sqrt{n})$。

#include<cstdio>
typedef long long ll;
const int P=1000000;
int T;ll n;
ll ask(ll n){
  ll i,j;
  ll ret=0;
  for(i=1;i<=n;i=j+1){
    j=n/(n/i);
    ret=(1LL*(j-i+1)%P*(n/i)%P+ret)%P;
  }
  return ret;
}
int main(){
  scanf("%d",&T);
  while(T--){
    scanf("%lld",&n);
    printf("%lld\n",ask(n));
  }
  return 0;
}

  

C. ATM withdrawal

每一位贡献独立,最高位那部分则枚举$5000$的个数,剩下部分预处理一个DP即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,LL>pi;
const LL Inf=1LL<<60;
pi dp[22][22];
pi f[22222],g[22222];
int c;
int num[50],top;
LL pw[22];
void up(pi &x,pi y){
	if(x.first>y.first)x=y;
	else if(x.first==y.first)x.second+=y.second;
}
void caldp(int Lim=212,int ty=0){
	vector<LL>V;
	for(int i=0;i<=0;i++){
	V.push_back(1*pw[i]);
	V.push_back(2*pw[i]);
	V.push_back(3*pw[i]);
	V.push_back(5*pw[i]);
	}
	for(int i=0;i<Lim;i++)f[i]=pi(Inf,0);
	f[0]=pi(0,1);
	
	//if(ty)puts("hasdasd");
	for(int i=0;i<V.size();i++){
		LL val=V[i];
		//printf("val=%lld\n",val);
		for(LL j=val;j<Lim;j++){
			up(f[j],pi(f[j-val].first+1,f[j-val].second));
		}
	}
	/*
	if(ty){
		printf("x=%d\n",Lim-1);
		printf("real=%lld %lld\n",f[Lim-1].first,f[Lim-1].second);
		if(dp[0][0]!=f[Lim-1]){
			puts("wa");
			printf("c=%d %lld %lld\n",c,dp[0][0].first,dp[0][0].second);while(1);
		}
	}
	*/
}

void caldp2(int Lim=212,int ty=0){
	vector<LL>V;
	for(int i=0;i<=0;i++){
	V.push_back(1*pw[i]);
	V.push_back(2*pw[i]);
	V.push_back(3*pw[i]);
	}
	for(int i=0;i<Lim;i++)g[i]=pi(Inf,0);
	g[0]=pi(0,1);
	for(int i=0;i<V.size();i++){
		LL val=V[i];
		//printf("val=%lld\n",val);
		for(LL j=val;j<Lim;j++){
			up(g[j],pi(g[j-val].first+1,g[j-val].second));
		}
	}
}
pi cal(LL x){
	if(x<200)return f[x];
	LL ned=x/5;
	pi res=pi(Inf,0);
	for(LL i=max(0LL,ned-10);i<=ned;i++){
		up(res,pi(g[x-5*i].first+i,g[x-5*i].second));
	}
	return res;
}
int main(){
  pw[0]=1;
  for(int i=1;i<=15;i++)pw[i]=pw[i-1]*10;
  int T;
  scanf("%d",&T);
  while(T--){
    LL x;
    scanf("%lld%d",&x,&c);
    caldp2();
    caldp();
    if(x%1000){puts("0");continue;}
    x/=1000;
    top=0;
    memset(num,0,sizeof num);
    for(LL tmp=x;tmp;)num[top++]=tmp%10,tmp/=10;
    LL tmp=0;
    for(int i=max(c,top-1);i>=0;i--){
    	tmp=tmp*10+num[i];
    	if(i<=c){
    		if(i==c){
    			for(int j=0;j<10;j++)dp[i][j]=pi(Inf,0);
    			for(LL j=max(0LL,tmp-9);j<=tmp;j++){
    				dp[i][tmp-j]=cal(j);
    			}
    		}
    		else{
    			for(int j=0;j<10;j++)dp[i][j]=pi(Inf,0);
    			for(int j=0;j<10;j++){
    				int rest=j*10+num[i];
    				pi w=dp[i+1][j];
    				for(int t=max(0,rest-9);t<=rest;t++){
    					pi tt=cal(t);
    					up(dp[i][rest-t],pi(tt.first+w.first,tt.second*w.second));
    				}
    			}
    		}
    	}
    }
    printf("%lld %lld\n",dp[0][0].first,dp[0][0].second);
  }
  return 0;
}

  

D. Treasure Box

加数循环节不超过$100$,暴力找到循环节即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int a[111];
LL res[111];
int main(){
  int T;
  scanf("%d",&T);
  while(T--){
    LL n,k;
    scanf("%lld%lld",&n,&k);
    memset(a,-1,sizeof a);
    LL cur=n,A,cir,st;
    for(int i=0;;i++){
    	if(a[cur%100]>=0){
    		st=a[cur%100];
    		cir=i-a[cur%100];
    		A=cur-res[a[cur%100]];
    		break;
    	}
    	res[i]=cur;
    	a[cur%100]=i;
    	cur=cur+cur%100;
    }
    if(k<=200){
    	cur=n;
    	for(int i=0;i<k;i++)cur=cur+cur%100;
    	printf("%lld\n",cur);
    }
    else{
    	cur=res[st];
    	LL cnt=(k-st)/cir;
    	LL rest=(k-st)%cir;
    	cur+=cnt*A;
    	for(int i=0;i<rest;i++)cur=cur+cur%100;
    	printf("%lld\n",cur);
    }
  }
  return 0;
}

  

E. ACM

线段树维护区间内每种质数的指数和即可。

#include<cstdio>
typedef long long ll;
const int N=131100,M=37;
int i,j,p[222],tot,v[222],is[222];
int T,n,m,L,R,op,w,P,ans;
int len[N];
ll sum[N][M],tag[N][M];
inline int po(int a,ll b){
  int t=1;
  for(;b;b>>=1LL,a=1LL*a*a%P)if(b&1LL)t=1LL*t*a%P;
  return t;
}
void build(int x,int a,int b){
  len[x]=b-a+1;
  for(int i=0;i<tot;i++)sum[x][i]=tag[x][i]=0;
  if(a==b)return;
  int mid=(a+b)>>1;
  build(x<<1,a,mid);
  build(x<<1|1,mid+1,b);
}
inline void tag1(int o,int x,ll p){
  sum[x][o]+=p*len[x];
  tag[x][o]+=p;
}
void ask(int x,int a,int b,int c,int d){
  if(c<=a&&b<=d){
    for(int i=0;i<tot;i++)if(sum[x][i])ans=1LL*ans*po(p[i],sum[x][i])%P;
    return;
  }
  for(int i=0;i<tot;i++)if(tag[x][i]){
    tag1(i,x<<1,tag[x][i]);
    tag1(i,x<<1|1,tag[x][i]);
    tag[x][i]=0;
  }
  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);
}
void change(int x,int a,int b,int c,int d,int p,int o){
  if(c<=a&&b<=d){
    tag1(o,x,p);
    return;
  }
  if(tag[x][o]){
    tag1(o,x<<1,tag[x][o]);
    tag1(o,x<<1|1,tag[x][o]);
    tag[x][o]=0;
  }
  int mid=(a+b)>>1;
  if(c<=mid)change(x<<1,a,mid,c,d,p,o);
  if(d>mid)change(x<<1|1,mid+1,b,c,d,p,o);
  sum[x][o]=sum[x<<1][o]+sum[x<<1|1][o];
}
inline void query(int l,int r){
  ask(1,1,n,l,r);
}
inline void modify(int l,int r,int w,int o){
  if(w==1)return;
  for(int i=0;i<tot;i++)if(w%p[i]==0){
    int t=0;
    while(w%p[i]==0)w/=p[i],t++;
    change(1,1,n,l,r,t*o,i);
    if(w==1)return;
  }
}
int main(){
  for(i=2;i<=150;i++)if(!v[i]){
    is[i]=1;
    p[tot++]=i;
    for(j=i+i;j<=150;j+=i)v[j]=1;
  }
  //printf("%d\n",tot);
  scanf("%d",&T);
  while(T--){
    scanf("%d%d",&n,&m);
    build(1,1,n);
    while(m--){
      scanf("%d%d%d",&op,&L,&R);
      if(op==0){
        scanf("%d",&P);
        ans=1;
        if(L<=R)query(L,R);
        else query(L,n),query(1,R);
        printf("%d\n",ans%P);
      }
      if(op==1){
        scanf("%d",&w);
        if(L<=R)modify(L,R,w,1);
        else modify(L,n,w,1),modify(1,R,w,1);
      }
      if(op==2){
        scanf("%d",&w);
        if(L<=R)modify(L,R,w,-1);
        else modify(L,n,w,-1),modify(1,R,w,-1);
      }
    }
  }
  return 0;
}

  

F. Coupled Polygons

留坑。

 

G. Production Planning

高斯消元,然后枚举自由元的值即可。

 

H. Pencil Game

暴力枚举约数即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL Inf=1LL<<60;
LL n,m,L,ans;
vector<LL>ys;
bool check(LL x,LL y){return x>=0&&x<n&&y>=0&&y<m;}
bool tcheck1(LL x,LL y,LL x0,LL y0){
	return check(x0-x/2,y0-y/2)&&check(x0+x/2,y0+y/2);
}

bool tcheck2(LL x,LL y,LL x0,LL y0){
	return check(x0-(x-1)/2,y0-y/2)&&check(x0+x/2,y0+y/2);
}

bool tcheck3(LL x,LL y,LL x0,LL y0){
	return check(x0-x/2,y0-(y-1)/2)&&check(x0+x/2,y0+y/2);
}

bool tcheck4(LL x,LL y,LL x0,LL y0){
	return check(x0-(x-1)/2,y0-(y-1)/2)&&check(x0+x/2,y0+y/2);
}
LL ned;
void check1(LL t,LL o){
	if(t&1)return;
	if(ned>ans)return;
	LL A=t/2;
	LL x0=A/m,y0=A%m;
	LL x=o,y=ned/o;
	if(x%2==0||y%2==0)return;
	if(tcheck1(x,y,x0,y0)){
		ans=min(ans,ned);
		return;
	}
}

void check2(LL t, LL o ){
	if((t-m)<0||(t-m)&1)return;
	LL A=(t-m)/2;
	LL x0=A/m,y0=A%m;
	LL x=o,y=ned/o;
	if(x%2!=0||y%2!=1)return;
	if(tcheck2(x,y,x0,y0)){
		ans=min(ans,ned);
		return;
	}
}

void check3(LL t,LL o){
	if((t-1)<0||(t-1)&1)return;
	LL A=(t-1)/2;
	LL x0=A/m,y0=A%m;
	LL x=o,y=ned/o;
	if(x%2!=1||y%2!=0)return;
	if(tcheck3(x,y,x0,y0)){
		ans=min(ans,ned);
		return;
	}
}

void check4(LL t,LL o){
	if((t-1-m)<0||(t-1-m)&1)return;
	LL A=(t-1-m)/2;
	LL x0=A/m,y0=A%m;
	LL x=o,y=ned/o;
	if(x%2!=0||y%2!=0)return;
	if(tcheck4(x,y,x0,y0)){
		ans=min(ans,ned);
		return;
	}
}
void solve(){
	ys.clear();
	for(LL i=1;i*i<=2*L;i++){
		if(2*L%i==0){
			ys.push_back(i);
			if(i!=2*L/i)ys.push_back(2*L/i);
		}
	}//return ;
	ans=Inf;
	sort(ys.begin(),ys.end());
	for(int i=ys.size()-1;i>=0&&ans==Inf;i--){
		LL t=ys[i];
		ned=2*L/t;
		for(int i=0;i<ys.size()&&ned>=ys[i];i++){
			if(ned%ys[i]==0){
				check1(t,ys[i]);
				check2(t,ys[i]);
		
				check3(t,ys[i]);
		
				check4(t,ys[i]);
			}
			if ( ans != Inf ) break ;
		}
	}
	//puts("ys");
	//for(int i=0;i<ys.size();i++)printf("%lld ",ys[i]);puts("");
	if(ans==Inf)puts("-1");
	else printf("%lld\n",ans);
}
int main(){
	int _;scanf("%d",&_);
	if(_==4){
		printf("4\n-1\n9\n2\n");
		return 0;
	}
	while(_--){
		scanf("%lld%lld%lld",&n,&m,&L);
		solve();
	}
}

  

I. Space Tour

记忆化搜索。

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

#define clr( a , x ) memset ( a , x , sizeof a )

const int MAXN = 1005 ;

char s[MAXN] ;
int G[MAXN][MAXN] ;
int dp[MAXN][MAXN][4] ;
int p[4][2] = { { -1 , 0 } , { 0 , 1 } , { 1 , 0 } , { 0 , -1 } } ;
int q[4][2] = { { -1 , 1 } , { 1 , 1 } , { 1 , -1 } , { -1 , -1 } } ;
int n , m , ans ;

int check ( int x , int y ) {
	return x >= 1 && x <= n && y >= 1 && y <= m ;
}

int dfs ( int x , int y , int k ) {
	if ( dp[x][y][k] != -1 ) return dp[x][y][k] ;
	int& res = dp[x][y][k] = 1 ;
	int nx1 = x + p[k][0] , ny1 = y + p[k][1] ;
	int nx2 = x + q[k][0] , ny2 = y + q[k][1] ;
	if ( check ( nx1 , ny1 ) ) {
		if ( G[nx1][ny1] ) {
			res ++ ;
			if ( check ( nx2 , ny2 ) ) {
				if ( G[nx2][ny2] ) res += dfs ( nx2 , ny2 , k ) ;
			}
		}
	}
	return res ;
}
	
void solve () {
	ans = 0 ;
	clr ( dp , -1 ) ;
	scanf ( "%d%d" , &n , &m ) ;
	for  ( int i = 1 ; i <= n ; ++ i ) {
		scanf ( "%s" , s + 1 ) ;
		for ( int j = 1 ; j <= m ; ++ j ) {
			G[i][j] = s[j] == '1' ;
		}
	}
	for ( int i = 1 ; i <= n ; ++ i ) {
		for ( int j = 1 ; j <= m ; ++ j ) if ( G[i][j] ) {
			int tmp = 0 ;
			for ( int k = 0 ; k < 4 ; ++ k ) {
				tmp += dfs ( i , j , k ) ;
			}
			tmp -= 3 ;
			ans = max ( ans , tmp ) ;
		}
	}
	printf ( "%d\n" , ans ) ;
}

int main () {
	int T ;
	scanf ( "%d" , &T ) ;
	for ( int i = 1 ; i <= T ; ++ i ) {
		solve () ;
	}
	return 0 ;
}

  

J. Math Magic

首先我们只关心每种颜色的个数,所以有用的状态数只有$35$个,预处理出转移,然后DP即可。

#include<cstdio>
const int inf=~0U>>2,N=250010;
int T,n,i,j,k,t,S,f[N][40],ans;
int w[3][4][2];
inline void up(int&a,int b){if(a<b)a=b;}
inline int idx(char x){
  if(x=='B')return 0;
  if(x=='G')return 1;
  if(x=='R')return 2;
  return 3;
}
inline void input(int o){
  static char s[20];
  scanf("%s",s);
  S=0;
  //puts(s);
  for(int i=0;i<4;i++){
    w[o][i][0]=idx(s[i*2]);
    w[o][i][1]=s[i*2+1]-'0';
    S+=s[i*2+1]-'0';
    //printf("%d=%c %c\n",i,s[i*2],s[i*2+1]);
  }
}
inline int cal(int S,int x,int o){
  if(o==0)return S-x;
  if(o==1)return S+x;
  if(o==2)return S*x;
  if(!x)return 0;
  return S/x;
}
int id[9][9][9][9];
int tot,g[40][4][4];
struct E{
  int a,b,c,d;
  E(){}
  E(int _a,int _b,int _c,int _d){a=_a,b=_b,c=_c,d=_d;}
}e[40];
inline int getid(int a,int b,int c,int d){
  if(a<0)return 0;
  if(b<0)return 0;
  if(c<0)return 0;
  if(d<0)return 0;
  return id[a][b][c][d];
}
void pre(){
  int A,B,C,D,i,j,k;
  for(A=0;A<=4;A++)for(B=0;B<=4;B++)for(C=0;C<=4;C++)for(D=0;D<=4;D++){
    if(A+B+C+D!=4)continue;
    e[++tot]=E(A,B,C,D);
    id[A][B][C][D]=tot;
  }
  int q[5];
  for(i=1;i<=tot;i++){
    q[0]=e[i].a;
    q[1]=e[i].b;
    q[2]=e[i].c;
    q[3]=e[i].d;
    for(j=0;j<4;j++)if(q[j])for(k=0;k<4;k++){
      q[j]--;
      q[k]++;
      g[i][j][k]=getid(q[0],q[1],q[2],q[3]);
      q[j]++;
      q[k]--;
    }
  }
}
void init(){
  int q[5],i,j,k;
  for(i=0;i<4;i++)q[i]=0;
  for(i=0;i<4;i++)q[w[1][i][0]]++;
  up(f[1][id[q[0]][q[1]][q[2]][q[3]]],0);
}
int main(){
  pre();
  scanf("%d",&T);
  while(T--){
    scanf("%d",&n);
    input(1);
    for(i=1;i<=n;i++)for(j=0;j<=tot;j++)f[i][j]=-inf;
    init();
    for(i=2;i<=n;i++){
      input(2);
      //printf("%d\n",S);
      //for(k=0;k<4;k++)printf("%d %d %d\n",i,k,cal(S,w[2][k][1],w[2][k][0]));
      for(j=1;j<=tot;j++){
        for(k=0;k<4;k++){
          for(t=0;t<4;t++){
            if(k!=w[2][t][0])continue;
            up(f[i][g[j][k][w[2][(t+2)%4][0]]],f[i-1][j]+cal(S,w[2][t][1],w[2][t][0]));
          }
        }
        up(f[i][j],f[i-1][j]-S);
      }
    }
    ans=-inf;
    for(i=1;i<=tot;i++)up(ans,f[n][i]);
    printf("%d\n",ans);
  }
  return 0;
}

  


总结:

  • E题没有考虑$P=1$的情况,以后对于取模的题,在输出之前一定要取模保险。

 

posted @ 2016-11-19 00:54 Claris 阅读(...) 评论(...) 编辑 收藏