[ NOIP 1998 ] TG

\(\\\)

\(\#A\) 车站


火车从第\(1\)站开出,上车的人数为\(a\),然后到达第\(2\)站,在第\(2\)站有人上、下车,但上、下车的人数相同,因此在第\(2\)站开出时(即在到达第\(3\)站之前)车上的人数保持为\(a\)人。从第\(3\)站起(包括第\(3\)站)上、下车的人数有一定规律:上车的人数都是前两站上车人数之和,而下车人数等于上一站上车人数,一直到第\(n-1\)站,都满足此规律。

共有\(N\)个车站,始发站上车的人数为\(a\),最后一站下车的人数是\(m\)(全部下车),问\(x\)站开出时车上的人数。

  • \(a,n,x\in [1,20]\)\(m\in [1,2000]\)
  • \(fib_i\)表示第\(i\)项斐波那契数的值(从第一项开始),推推式子发现:
    • 第一站和第三站上车\(a\)
    • 第二站增加\(0\)人,设上车\(b\)
    • 第四站增加\(b\)
    • \(5\text~n-1\)站中,第\(i\)站人数增量为\(fib_{i-4}-fib_{i-3}\)
  • 暴力累加到第\(n-1\)项,回代求出\(b\),在退回到第\(x\)次即可。
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 30
#define R register
using namespace std;

int a,n,m,x;
int ax=2,ay,ansx,ansy,fib[N]={0,1,1};

int main(){
  scanf("%d%d%d%d",&a,&n,&m,&x);
  if(x<=2){printf("%d\n",a);return 0;}
  if(x==3){printf("%d\n",2*a);return 0;}
  for(R int i=3;i<N;++i) fib[i]=fib[i-1]+fib[i-2];
  for(R int i=4;i<n;++i){
    ax+=fib[i-4]; ay+=fib[i-3];
    if(i==x) ansx=ax,ansy=ay;
  }
  m-=ax*a; m/=ay;
  printf("%d\n",ansx*a+ansy*m);
  return 0;
}

\(\\\)

\(\#B\) 拼数


设有\(N\)个正整数,将它们联接成一排,组成一个最大的多位整数。

  • \(N\in [0,20]\)
  • 按字典序排序所有串即可,巧妙地实现方式可以通过字符串相加比较大小。
#include<iostream>
#include<cstdio>
#include<cmath> 
#include<cstring>
#include<algorithm>
using namespace std;
string s[50];
bool cmp(string a,string b){
	return a+b>b+a;
}
int main(){
	int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)cin>>s[i];
    sort(s+1,s+n+1,cmp);
    for(int i=1;i<=n;i++) cout<<s[i];
    printf("\n");
    return 0;
}

\(\\\)

\(\# C\) 进制位


给出了如下的一张\(N\times N\)的加法表,表中的字母代表数字。 例如:

+    L    K    V    E
L    L    K    V    E
K    K    V    E    KL
V    V    E    KL    KK
E    E    KL    KK     KV

试求出每一个字母所代表数字及运算的进制。

  • \(N\in [0,9]\)
  • \(9!=362880\),并不会超时,所以直接通过搜索枚举每一个字母所代表数字,最后暴力验证即可。
  • 如果该表合法,则进制位必然为\(N-1\)进制,因为进位必定会产生\(1\),而\(1\)必定会累加出其他的数。
  • 验证时注意进位不能在十进制下进位,需要模拟\(N-1\)进制的进位过程。
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 30
#define R register
#define gc getchar
using namespace std;

char s[N][N][N];

bool vis[N],use[N];

int n,m,q[N],trs[N],len[N][N];

inline bool check(){
  for(R int i=1;i<n;++i)
    for(R int j=1;j<n;++j){
      int x=0,y=0,z=0;
      for(R int k=0;k<len[0][j];++k) x=x*10+trs[s[0][j][k]-'A'+1];
      for(R int k=0;k<len[i][0];++k) y=y*10+trs[s[i][0][k]-'A'+1];
      while(x||y){
        z=z*10+(x%10+y%10)%(n-1);
        z+=((x%10+y%10)>=n-1)?10:0;
        x/=10; y/=10;
      }
      x=z; z=0;
      for(R int k=0;k<len[i][j];++k) z=z*10+trs[s[i][j][k]-'A'+1];
      if(x!=z) return 0;
    }
  return 1;
}

inline bool dfs(int t){
  if(t==q[0]+1){
    if(check()){
      for(R int i=1;i<n;++i)
        printf("%c=%d ",s[0][i][0],trs[s[0][i][0]-'A'+1]);
      printf("\n%d\n",n-1); return 1;
    }
    return 0;
  }
  for(R int i=0;i<n-1;++i)
    if(!use[i]){
      use[i]=1; trs[q[t]]=i;
      if(dfs(t+1)) return 1;
      use[i]=0; trs[q[t]]=0;
    }
  return 0;
}
int main(){
  scanf("%d",&n);
  for(R int i=0;i<n;++i)
    for(R int j=0;j<n;++j){
      scanf("%s",s[i][j]);
      for(R int k=0;k<(int)strlen(s[i][j]);++k){
        if(!isalpha(s[i][j][k])){len[i][j]=k;break;}
        else vis[s[i][j][k]-'A'+1]=1;
      }
      if(!len[i][j]) len[i][j]=strlen(s[i][j]);
    }
  for(R int i=0;i<=27;++i) if(vis[i]) q[++q[0]]=i;
  if(!dfs(1)) puts("ERROR!");
  return 0;
}

posted @ 2018-09-03 15:33  SGCollin  阅读(225)  评论(0编辑  收藏  举报