ACM ICPC Vietnam National Second Round

时间:2022-01-09 18:22:26

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$的情况,以后对于取模的题,在输出之前一定要取模保险。