NOIp 前N天做题

时光匆匆匆匆啊,离NOIp2015 只有不到一周了,我想想我好像什么都不知道啊,啊啊啊啊啊啊啊怎么办。。。。
我还是好好分析下这几天的模拟题吧。

分数化小数

【题目描述】
写一个程序,输入一个形如N/D的分数(N是分子,D是分母),输出它的小数形式。如果小数有循环节的话,把循环节放在一对括号中,例如:
1/3=33333333 写成0.(3)
41/333=0.123123123… 写成0.(123)
用xxx.0表示整数
典型的转化例子:
1/3=0.(3)
22/5=4.4
1/7=0.(142857)
2/2=1.0
3/8=0.375
45/56=0.803(571428)
【输入格式】
单独的一行包括被空格分开的N和D,1≤N,D≤100000。
【输出格式】
输出一行,小数的表示方法上面已经说得很明白了。
【样例输入】
45 56
【样例输出】
0.803(571428)

分析:
拿到这一个题 分析 分析
模拟模拟一定是模拟 找一个分数值
先找到整数部分,然后按除法该怎么算就怎么模拟。
然后判断一下各种情况。
最后一个问题就是 循环在哪(我们都知道一个有理数must能写成分数形式 反之一样)所以一定有。而当算除法剩下的那个数(余数)与前面相同时is the answer。

就素这样
顺便背背读入优化…..其实没用

#include
#include
#include
#include
using namespace std;

int read(){
 int x=0,f=1;char ch=getchar();
 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
 return x*f;
}

void init()
{ freopen("fracdec.in","r",stdin);
  freopen("fracdec.out","w",stdout);  
}

int n,d;// n/d
int itg,mo,xs[100000],ys[100000],lens;
int main(){
    init();
    bool flag=0;
    n=read();d=read();
    itg = n/d;
    mo=n-itg*d;
    int len=1;
    if(mo == 0)
    {
    printf("%d.0",itg);
    return 0;
    }
    else {
      while(len<100000)
      {
      ys[len] = mo; 
      for(int i=1 ;iif(mo == ys[i]){
        lens = i; 
        flag = 1;
        break;}
        }
      mo*=10;
      xs[len] = mo/d;
      mo-=xs[len]*d;
      len++;
      if(flag ==1){
       printf("%d.",itg);
       for(int i=1 ;iprintf("%d",xs[i]);
       printf("(");
       for(int i=lens;i1;i++)
       printf("%d",xs[i]);
       printf(")");
       return 0;
      }
      if(mo == 0){
      printf("%d.",itg);
      for(int i=1 ;iprintf("%d",xs[i]);
      return 0;
      }
      }
      } 
 return 0;
}

覆盖墙壁

NOIp 前N天做题_第1张图片

给定N,要求计算2*N的墙壁的覆盖方法。由于结果很大,所以只要求输出最后4位。例如2*13的覆盖方法为13465,只需输出3465即可。如果答案少于4位,就直接输出就可以,不用加0,如N=3时输出5。

【输出格式】
一个整数N(1≤N≤1000000),表示墙壁的长。

【输出格式】
输出覆盖方法的最后4位,如果不足4位就输出整个答案。

【样例输入】
13

【样例输出】
3465

分析:
额 一看到题 额 我先做下一题吧。。。。状压吗 额 一直都不会额
额 dfs 暴力搜索 好主意 额 dfs 也学得差 暴力怎么写
要不乱搞打表……..
仔细读完题 N 好大
一定是dp 递推什么的
恩恩 想想想想想
好的 我发现了
我们定义 个 dp[i][3] i 铺到多少 0 上面没铺 2下面没铺 1铺完了
转移 如果智力不够就画画图………反正可以转移
dp[i][0]=dp[i-2][1] +dp[i-2][2]
dp[i][1]=dp[i-2][1]+dp[i-1][1]+dp[i-1][0]+dp[i-2][2]
dp[i][2]=dp[i][0]+dp[i-1][1]

then code

#include
#include
#include
#include
using namespace std;
const int M= 10000;
void init()
{ freopen("wall.in","r",stdin);
  freopen("wall.out","w",stdout);  
}
int f[1000005][3];
int n;
int main(){
  init();
  scanf("%d",&n);
  f[0][1] = 1;
  for(int i=1 ;i<=n ;i++)
  { if(i-2>=0)f[i][0] += f[i-2][1]+f[i-2][2];
    f[i][1] +=f[i-1][1]+f[i-1][0];
    if(i-2>=0)f[i][1] += f[i-2][1]+f[i-2][2];
    f[i][2] += f[i][0]+f[i-1][1];
    for(int j=0 ;j<=2;++j)
    f[i][j] %= M;
  }
  printf("%d",f[n][1]);
  return 0; 
}

独木桥

【问题描述】
战争已经进入到紧要时刻。你是运输小队长,正在率领运输部队向前线运送物资。运输任务像做题一样无聊。你希望找些刺激,于是命令你的士兵们到前方的一座独木桥上欣赏风景,而你留在桥下欣赏士兵们。士兵们十分愤怒,因为这座独木桥十分狭窄,只能容纳一个人通过。假如有两个人相向而行在桥上相遇,那么他们两人将无法绕过对方,只能由一个人回头下桥,让另一个人先通过。但是,可以有多个人同时呆在同一个位置。
突然,你收到从指挥部发来的信息,敌军的轰炸机正朝着你所在的独木桥飞来!为了安全,你的部队必须撤下独木桥。独木桥的长度为L,士兵们只能呆在坐标为整数的位置,所有士兵的速度都为1,当一个士兵某一时刻来到了坐标为0或L+1的位置时,他就离开了独木桥。
每个士兵都有一个初始面对的方向,他们会以匀速朝着这个方向行走,中途不会自己改变方向。但是,如果两个士兵面对面相遇,他们无法彼此通过对方,于是就分别转身,继续行走。转身不需要任何时间。
由于先前的愤怒,你已不能控制你的士兵。甚至,你连每个士兵初始面对的方向都不知道。因此,你想要知道你的部队最少需要多少时间就可能全部撤离独木桥。另外,总部也在安排阻拦敌人的进攻,因此你还需要知道你的部队最多需要多少时间才能全部撤离独木桥。

【输入文件】
第一行:一个整数L,表示独木桥的长度。桥上的坐标为1..L
第二行:一个整数N,表示初始时留在桥上士兵的数目。
第三行:有N个整数,分别表示每个士兵的初始坐标。初始时,没有两个士兵在同一坐标。

【输出文件】只有一行,输出两个整数,分别表示部队撤离独木桥的最小时间和最大时间。两个整数用一个空格分开。

【样例输入】
4
2
1 3

【样例输出】
2 4

【数据规模及约定】
N≤L≤10000

没记错的话这是很经典的一类数学思考题
但是我做错了………
额 好像跟蚂蚁爬树这种题很相似
恩 其实转向什么的想想知道根本不用管

#include
#include
#include
#include
using namespace std;
const int M= 10000;

void init()
{ freopen("bridge.in","r",stdin);
  freopen("bridge.out","w",stdout);  
}
int n,l;
bool a[10005];

int main(){
  init();
  memset(a,0,sizeof(a));
  scanf("%d%d",&l,&n);
  if(n==0){
   printf("0 0");
   return 0;
  }
  for(int i=1 ;i<=n ;i++)
  { int x; 
    scanf("%d",&x);
    a[x] = 1;
  }

  int mid = l/2+1;
  int L=mid,R=mid;
  int ans,ans1=-9999,ans2=-9999;
  bool fl = 0,fr = 0;

  for(int i=mid ;i<=l;i++)
  {if(a[i]==1){ans1=l-i+1;break;}
  }
  for(int i=mid-1 ;i>=1 ;i--)
  {if(a[i]==1){ans2=i;break;}
  }
  ans = max(ans1,ans2);  

  int mans,mans1=-9999,mans2=-9999;
  for(int i=1 ;i<=l;i++)
  if(a[i]==1){mans1=l-i+1;
              break;}
  for(int i=l;i>=1 ;i--)
  if(a[i]==1){mans2=i;break;
  }
  mans = max(mans1,mans2);
  printf("%d %d",ans,mans);
  return 0;
}

分配小组

【问题描述】
有N个Mars人想要进行一项活动。他们需要分成几个小组,每个人属于其中一个小组。Mars人从出生起每个人就有一个印记,这个印记是个正整数。如果B的印记是A的倍数,那么B就是A的父亲,与地球人的定义不同,一个Mars人可以有多个父亲。特别的,A不是自己的父亲,但是所有其他与A的印记相同的人都是A的父亲。因此,除了A自己,A的父亲的父亲都是A的父亲。
Mars人十分强调子女的独立,因此进行这项活动的分组时,任何人都不能和自己的父亲分到同一小组。你的任务就是对于给定的N个Mars人,给出一种分组方案,使得小组的数量最少。显然,这个问题一定存在可行解——你可以让每个Mars人单独一组。如果有多解,任意输出一组即可。
【输入文件】
第一行:一个整数N,表示Mars人的数量。
接下来一行有N个正整数,表示每个Mars人的印记。
【输出文件】
只有一行是一个整数K,表示你分成的最少小组数量。

【样例输入】
5
1 1 3 1 5

【样例输出】
4

【样例说明】
分组情况:
第1组:1
第2组:1
第3组:1
第4组:3 5
三个1必须各自分别分成一组;3和5不是倍数关系,可以分成一组。

【数据规模及约定】
N≤5000
1≤所有的印记≤5000
对于每个测试点,你给出的分组必须是合法的,且恰好和你的小组数量相等,否则本测试点得0分。
如果你给出的小组数量和标准答案相同,则本测试点得10分,否则本测试点得0分。

【样例输入2】
10
1 2 3 5 6 9 10 6 9 9
【样例输出2】
5

【样例2说明】
分组:
第1组:1
第2组:2 3 5
第3组:6 9 10
第4组:6 9
第5组:9

读完题 看看样例大致也就懂了
也就是求一求要分成多少组 满足每组里面没有数能被改组里面的数整除。 这样可以考虑一下是dp
dp[i]第i个数
先sort()小到大
然后只有可能是后面的数来%前面的数为0;
所以if(a[i]%a[j]==0)dp[i] = max(dp[i],dp[j]+1)

大致是

#include
#include
#include
#include
using namespace std;
const int M= 10000;

void init()
{ freopen("poset.in","r",stdin);
  freopen("poset.out","w",stdout);  
}

int n;
int a[5005];
int f[5005];
int ans=-99999;
int main(){
 init();
 scanf("%d",&n);
 for(int i=1 ;i<=n ;i++)
 {
   scanf("%d",&a[i]);
 }
 sort(a+1,a+n+1);

  for(int i=1 ;i<=n ;i++)f[i] = 1;

   for(int i=2 ;i<=n ;i++)
    for(int j=1 ;jif(a[i]%a[j]==0) 
       f[i] = max(f[i] ,f[j]+1);
       ans = max(ans,f[i]);
       }     
 printf("%d",ans);
 return 0;  
}

我懒得去掉freopen了…..讲究看。

你可能感兴趣的:(习题)