【11/8】模拟赛

第一题 符文之语

【题目描述】

当小 FF来到神庙时,神庙已经破败不堪了。但神庙的中央有一个光亮如新的石台。小 FF走近石台,发现石台上有一个数串,而数串的上方刻着一串古老的符文之语。精通古符文之语的小 FF不费吹灰之力就读懂了文章的意思,其大意是:对于石台上的一串数字,你可以在适当的位置加入乘号(设加了 k个,当然也可不加,即分成k+1个部分),设这k+1个部分的乘积(如果k=0,则乘积即为原数串的值)对m的余数(即 mod m)为 x;现求 x能达到的最小值及该情况下k的最小值,以及 x能达到的最大值及该情况下的 k的最小值(可以存在 x的最小值与最大值相同的情况)。

小FF还知道,如果他找到了正确的答案,那么就可以通往神庙的下层了。但这个问题似乎不太好解决,小 FF就找到了你,并答应找到财宝以后和你二八分(当然你拿二……)。

 

【输入格式】

第一行为数串,且数串中不存在 0;

第二行为 m.

 

【输出格式】

四个数,分别为 x的最小值和该情况下的 k,以及 x的最大值和该情况下的 k,相邻

两个数之间用一个空格隔开。

 

【样例输入】

4421

22

 

【样例输出】

0 1 21 0

 

【数据范围】

对于 30%的数据: 2 <=字符串长度 L<=50.

对于100%的数据: 2 <=字符串长度 L<=1000;

2<=m<=50.

 

【分析】

f[i][j]代表从1到i,达到j这个余数,所需要的最少的乘号个数。

预处理b[i][j]代表从i到j的数字对m的余数。

 

第二题 最接近神的人

【题目描述】

破解了符文之语,小 FF开启了通往地下的道路。当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一副古代人进行某种活动的图案。而石门上方用古代文写着“神的殿堂“。小 FF猜想里面应该就有王室的遗产了。但现在的问题是如何打开这扇门……

仔细研究后,他发现门上的图案大概是说:古代人认为只有智者才是最容易接近神明的。而最聪明的人往往通过一种仪式选拔出来。仪式大概是指,即将隐退的智者为他的候选人写下一串无序的数字,并让他们进行一种操作,即交换序列中相邻的两个元素。而用最少的交换次数使原序列变成不下降序列的人即是下一任智者。

小 FF发现门上同样有着 n个数字。于是他认为打开这扇门的秘诀就是找到让这个序列变成不下降序列所需要的最小次数。但小 FF不会……只好又找到了你,并答应事成之后与你三七分……

 

【输入格式】

第一行为一个整数 n,表示序列长度

第二行为 n个整数,表示序列中每个元素。

 

【输出格式】

一个整数 ans,即最少操作次数。

 

【样例输入】

4

2 8 0 3

 

【样例输出】

3

 

【数据范围】

对于 30%的数据 1<= n <= 10^4.

对于 100%的数据 1 <= n <= 5*10^5;

-maxlongint <= A[i ]<= maxlongint

 

【分析】

重要的条件是只有相邻的才可以交换。统计逆序对的个数就是答案。

 

第三题 古代人的难题

【题目描述】

门打开了,里面果然是个很大的厅堂。但可惜厅堂内除了中央的一张羊皮纸和一根精致的石笔,还有周围几具骷髅外什么也没有。难道这就是王室的遗产?小 FF不信,他仔细阅读了羊皮纸上的内容后发现,里面书写的古代人一直没能解出的难题,解除这道题目的人只要将答案用石笔写到这张羊皮纸上就能到达王室的宝藏室了。而当小FF拿起石笔后,刚刚打开的巨石门突然关上了。这时小 FF意识到原来那几具骷髅是在他之前到这里的冒险者,恐怕是因为没能破解这道题而困死在这里了。小 FF越想越害怕,急忙联系到了你,为了能保命,他甚至愿意和你五五分……看来你不得不再次帮他了。羊皮纸上的问题如下:已知 x, y为整数,且满足以下两个条件:

1. x, y ∈[1..k],且 x,y,k ∈Z;

2.(x^2 –xy – y^2)^2 =1

给你一个整数 k,求一组满足上述条件的x, y并且使得 x^2 +y^2的值最大。当小FF得到答案后,用石笔将答案书写在羊皮纸上,那么就能到达王室的遗产所在地了。

 

【输入格式】

一个整数 k

 

【输出格式】

输出文件仅一行,两个整数;两个整数分别表示 x和 y。x, y之间用一个空格隔开。

 

【样例输入】

1995

 

【样例输出】

1587 987

 

【数据范围】

对于 30%的数据: 2<=k<=10^4.

对于 100%的数据: 2<=k<=10^18.

 

【分析】

引自北极天南星。原文链接:http://starforever.blog.hexun.com/2762343_d.html

这道题如果直接枚举肯定会超时。

对条件二变形:

(n2-mn-m2)2

=[(m+n)2-mn-2n2]2

=[(m+n)2-mn-n2-n2]2

=[(m+n)2-n(m+n)-n2]2

我们发现,对于一组满足条件二的(m,n),(n,m+n)同样可以满足条件二。

同理,(n-m,m)也满足条件二。

这样,数列A={n-m,m,n,m+n}中任意相邻两项均满足条件二,而A是类Fibonacci数列。

考虑边界,因为(1,1)满足条件二,则A就是标准的Fibonacci数列。

又m,n均大于0。要使m2+n2最大,则取m,n为Fibonacci数列中[1,k]范围内最大的两个相邻数列。

 

第四题 宝物筛选

【题目描述】

终于,破解了千年的难题。小FF 找到了王室的宝物室,里面堆满了无数价值连城的宝物……这下小FF 可发财了,嘎嘎。但是这里的宝物实在是太多了,小FF 的采集车似乎装不下那么多宝物。看来小FF 只能含泪舍弃其中的一部分宝物了……小FF 对洞穴里的宝物进行了整理,他发现每样宝物都有一件或者多件。他粗略估算了下每样宝物的价值,之后开始了宝物筛选工作:小FF 有一个最大载重为W 的采集车, 洞穴里总共有n 种宝物的,每种宝物的价值为v [i], 重量为w[i], 每种宝物有m[i]件。小FF 希望在采集车不超载的前提下,选择一些宝物装进采集车,使得它们的价值和最大。

 

【输入格式】

第一行为2 整数N 和W,分别表示宝物种数和采集车的最大载重。

接下来n 行每行三个整数, 其中第i 行第一个数表示第i 类品价值, 第二个整数表示一件该类物品的重量, 第三个整数为该类物品数量。

 

【输出格式】

输出仅一个整数ans, 表示在采集车不超载的情况下收集的宝物的最大价值。

 

【样例输入】

4 20

3 9 3

5 9 1

9 4 2

8 1 3

 

【样例输出】

47

 

【数据范围】

对于30%的数据: n <= Σm[i] <= 10^4; 0 <= W <=10^3.

对于100%的数据: n <= Σm[i] <=10^5; 0<= W <=4 * 10^4;

1 <= n <= 100.

 

【分析】

有个数限制的背包。详见背包九讲。

 

代码

第一题

#include <stdio.h>
#include <string.h>
#define MAXINT 100000
#define maxn 1010
int f[maxn][50];
int b[maxn][maxn];
int n,m;
char s[maxn];
int tem;
int main()
{
  freopen("chars.in","r",stdin);
  freopen("chars.out","w",stdout);
  scanf("%s%d",s,&m);
  n = strlen(s);
  for (int i = 0;i < n;++i)
    for (int j = 0;j < m;++j)
      f[i][j] = MAXINT;
  for (int i = 0;i < n;++i) {
    tem = (tem * 10 + s[i] - '0') % m;
    f[i][tem] = 0;
  }
  for (int i = 0;i < n;++i) {
    tem = 0;
    for (int j = i;j < n;++j) {
      tem = (tem * 10 + s[j] - '0') % m;
      b[i][j] = tem;
    }
  }
  for (int i = 0;i < n;++i)
    for (int j = 0;j < m;++j)
      if (f[i][j] < MAXINT)
        for (int k = i + 1;k < n;++k) {
          tem = (j * b[i + 1][k]) % m;
          if (f[i][j] + 1 < f[k][tem]) f[k][tem] = f[i][j] + 1;
        }
  for (int i = 0;i < m;++i)
    if (f[n - 1][i] < MAXINT) {
      printf("%d %d ",i,f[n - 1][i]);
      break;
    }
  for (int i = m - 1;i >= 0;--i)
    if (f[n - 1][i] < MAXINT) {
      printf("%d %d\n",i,f[n - 1][i]);
      break;
    }
  return 0;
}

第二题

#include <stdio.h>
#define MAXN 500010
int a[MAXN],b[MAXN];
long long n,ans;
void solve(int l,int r) {
  if (l >= r)
    return;
  int mid = (l + r) / 2;
  solve(l,mid);
  solve(mid + 1,r);
  int i = l,j = mid + 1;
  for (int p = l;p <= r;++p)
    if ((i <= mid) && ((j > r) || (a[i] <= a[j])))
      b[p] = a[i++];
    else {
      b[p] = a[j++];
      ans += mid - i + 1;
    }
  for (i = l;i <= r;++i)
    a[i] = b[i];
}
int main() {
  freopen("sophist.in","r",stdin);
  freopen("sophist.out","w",stdout);
  scanf("%d",&n);
  for (int i = 1;i <= n;++i)
    scanf("%d",&a[i]);
  solve(1,n);
  printf("%lld\n",ans);
  return 0;
}

第三题

#include <stdio.h>
unsigned long long x,y,k,t;
int main() {
  freopen("puzzle.in","r",stdin);
  freopen("puzzle.out","w",stdout);
  scanf("%I64d",&k);
  x = 1;
  while (x + y <= k) {
    t = x + y;
    y = x;
    x = t;
  }
  printf("%I64d %I64d\n",x,y);
  return 0;
}

第四题

#include <stdio.h>
#define MAXN 110
int tv,tw,tm,n,ww,tot;
int v[100010],w[100010],f[100010];
int main() {
  freopen("treasure.in","r",stdin);
  freopen("treasure.out","w",stdout);
  scanf("%d%d",&n,&ww);
  for (int i = 1;i <= n;++i) {
    scanf("%d%d%d",&tv,&tw,&tm);
    int k = 0;
    while ((1 << k) <= tm) {
      v[++tot] = (1 << k) * tv;
      w[tot] = (1 << k) * tw;
      tm -= (1 << (k ++));
    }
    if (tm) {
      v[++tot] = tm * tv;
      w[tot] = tm * tw;
    }
  }
  for (int i = 1;i <= tot;++i)
    for (int j = ww;j >= w[i];--j)
      if (f[j - w[i]] + v[i] > f[j])
        f[j] = f[j - w[i]] + v[i];
  printf("%d\n",f[ww]);
  return 0;
}


posted @ 2010-11-08 15:10  Sephiroth.L.  阅读(630)  评论(0编辑  收藏  举报