一些奇思妙想的模拟题

来源:互联网 发布:网络协议的四层模型 编辑:程序博客网 时间:2024/04/28 07:51

HDU1005

A number sequence is defined as follows:

f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7.

Given A, B, and n, you are to calculate the value of f(n).
分析:
开始的时候想,计算的过程中直接mod7可以防止溢出,后来发现爆内存,因为数很小,是有规律的,如果连续的两个数都和前面连续的两个数都相同了,那么后面的数一定也相同,构成循环。
因此最重要的是要找出循环节。

int rec[60];int main(){    int a, b, n;    rec[0] = rec[1] = rec[2] = 1;    while( scanf( "%d %d %d", &a, &b, &n ), a | b | n ){        int beg, end, flag = 0;        for( int i = 3; i <= n && !flag; ++i ){            rec[i] = ( a * rec[i-1] + b * rec[i-2] ) % 7;            for( int j = 2; j <= i - 1; ++j ){                if( rec[i] == rec[j] && rec[i-1] == rec[j-1] ){                    beg = j, end = i;                    flag = 1;                    break;                }            }        }        if( flag ){            printf( "%d\n", rec[beg+(n-end)%(end-beg)] );        }        else            printf( "%d\n", rec[n] );    }    return 0;}

HDU1014

题意:
seed(x+1) = [seed(x) + STEP] % MOD
seed(1)=0;
给定STEP和MOD判断是否能产生布满0-(MOD-1)区间的所有值
如果STEP和MOD在这个区间内部有大于1的公约数,那么就不可能产生布满整个区间的数,实际上,如果公约数是x那么,最后相邻两个数的值就是x
10,15最后只能有0,5,

bool f(int x,int y){    int m=x%y;    if(m==0)return false;    for(int i=2;i<=m;i++)    {        if(x%i==0&&y%i==0)            return false;    }    return true;}

HDU1061

求N*N的最后一个数字是什么,
对于每一个阿拉伯数字0-9,求n次方都会有周期。

POJ1006

These three cycles are the physical, emotional, and intellectual cycles, and they have periods of lengths 23, 28, and 33 days,
给定三个高峰发生的时期,和一个给定的天d,计算下一个高峰距离这个d有多少天?

int a,b,c,d;    int cnt=0;    while(cin>>a>>b>>c>>d){      if(a==-1&&b==-1&&c==-1&&d==-1){        break;      }      cnt++;      while(b>d){        b=b-28;      }       while(a>d){        a=a-23;      }       while(c>d){        c=c-33;      }      int res;      for(int i=1;;i++){        if(((23*i+a-b)%28==0)&&((23*i+a-c)%33==0)){            if(23*i+a>d){ res=23*i+a;break;}        }      }

POJ3684,POJ1852

1,模拟自由落体的小球碰撞
2,模拟蚂蚁碰撞后原路返回
关键点在于:可以忽略一切碰撞,直接按照没有发生碰撞处理。

POJ1166

给定一些钟表,ABCDEFGHI,每个钟表有0,1,2,3代表时间,移动一个数字可以改变对应的钟表

1         ABDE 2         ABC 3         BCEF 4         ADG 5         BDEFH 6         CFI 7         DEGH 8         GHI 9         EFHI    

判断为了让钟表还原成0需要的最少的步数。
4^9可以枚举

for(int i=1;i<=9;i++){scanf("%d",a+i);}    for(b[1]=0;b[1]<=3;b[1]++)    for(b[2]=0;b[2]<=3;b[2]++)    for(b[3]=0;b[3]<=3;b[3]++)    for(b[4]=0;b[4]<=3;b[4]++)    for(b[5]=0;b[5]<=3;b[5]++)    for(b[6]=0;b[6]<=3;b[6]++)    for(b[7]=0;b[7]<=3;b[7]++)    for(b[8]=0;b[8]<=3;b[8]++)    for(b[9]=0;b[9]<=3;b[9]++) {                    c[1]=(a[1]+b[1]+b[2]+b[4])%4;                    c[2]=(a[2]+b[1]+b[2]+b[3]+b[5])%4;                    c[3]=(a[3]+b[2]+b[3]+b[6])%4;                    c[4]=(a[4]+b[1]+b[4]+b[5]+b[7])%4;                    c[5]=(a[5]+b[1]+b[3]+b[5]+b[7]+b[9])%4;                    c[6]=(a[6]+b[3]+b[5]+b[6]+b[9])%4;                    c[7]=(a[7]+b[4]+b[7]+b[8])%4;                    c[8]=(a[8]+b[5]+b[7]+b[8]+b[9])%4;                    c[9]=(a[9]+b[6]+b[8]+b[9])%4;                    if(c[1]+c[2]+c[3]+c[4]+c[5]+c[6]+c[7]+c[8]+c[9]==0){                        int i=-1;                        for(i=0;i<b[1];i++) printf("1 ");                        for(i=0;i<b[2];i++) printf("2 ");                        for(i=0;i<b[3];i++) printf("3 ");                        for(i=0;i<b[4];i++) printf("4 ");                        for(i=0;i<b[5];i++) printf("5 ");                        for(i=0;i<b[6];i++) printf("6 ");                        for(i=0;i<b[7];i++) printf("7 ");                        for(i=0;i<b[8];i++) printf("8 ");                        for(i=0;i<b[9];i++) printf("9 ");                        printf("\n");                    }    }

POJ1013

称量乒乓球
一些乒乓球有一个质量不合格,或者是大或者是小,
给定左边和右边乒乓球的关系,左边重还是右边重,还是相等。找出这个球,是轻了,还是重了。

一开始想到的方法,是假设是重的球或者是轻的球,但是后来发现,需要进行两次模拟,比较繁琐。于是采用了如下巧妙的思路:
初始值设置为0
如果是左边的重了,将左边的每个球的偏移量+1,右边的每个球偏移量-1,如果是相等的,那么就不考虑。
最后统计偏移量绝对值最大的那个,根据正负,判断是重了,还是轻了。

for(int i=1;i<=12;i++){    zero[i]=t[i]=0;}for(int now=1;now<=3;now++){    cin>>l>>r>>d;    if(d=="even"){        for(int i=0;i<l.size();i++){zero[l[i]-64]=1;}//标记为真说明,以后不用考虑了,因为一定是真的        for(int i=0;i<r.size();i++){zero[r[i]-64]=1;}    }    if(d=="up"){        for(int i=0;i<l.size();i++){t[l[i]-64]++;}        for(int i=0;i<r.size();i++){t[r[i]-64]--;}    }    if(d=="down"){        for(int i=0;i<l.size();i++){t[l[i]-64]--;}        for(int i=0;i<r.size();i++){t[r[i]-64]++;}    }}int max=-1;int index=-1;for(int i=1;i<=12;i++){    if(zero[i]==0&&fabs(t[i])>max){        index=i;        max=fabs(t[i]);    }}if(t[index]>0)printf("%c is the counterfeit coin and it is heavy.\n",index+64);else printf("%c is the counterfeit coin and it is light.\n",index+64);

POJ2586

题意:不太好理解。有一个公司由于某个病毒使公司赢亏数据丢失,但该公司每月的赢亏是一个定数,要么一个月赢利s,要么一月亏d。现在ACM只知道该公司每五个月有一个赢亏报表,而且每次报表赢利情况都为亏。在一年中这样的报表总共有8次(1到5,2到6,…,8到12),现在要编一个程序确定当赢s和亏d给出,并满足每张报表为亏的情况下,全年公司最高可赢利多少,若存在,则输出多多额,若不存在,输出”Deficit”。
算法:枚举。既然盈亏是定数,可以想到可能出现的情况就那么几种,进而想到枚举。

              x=1:  ssssd,ssssd,ss    d>4s     赢利10个月  10s-2d              x=2:  sssdd,sssdd,ss    2d>3s    赢利8个月     8s-4d              x=3:  ssddd,ssddd,ss    3d>2s    赢利6个月     6s-6d              x=4:  sdddd,sdddd,sd    4d>s     赢利3个月     3s-9d              x=5:  ddddd,ddddd,dd    4d<s     无赢利
 #include <iostream>using namespace std;int main(){    int s, d;    int sNum, dNum;    while (scanf("%d%d", &s, &d) != EOF)    {     if (d > 4*s)     {         sNum = 10;         dNum = 2;     }     else if (2*d > 3*s)     {         sNum = 8;         dNum = 4;     }     else if (3*d > 2*s)     {         sNum = 6;         dNum = 6;     }     else if (4*d > s)     {         sNum = 3;         dNum = 9;     }     else      {         sNum = 0;         dNum = 12;     }     int sum = sNum*s - dNum*d;     (sum>0)? cout << sum << endl : cout << "Deficit"<<endl;    }}

POJ2393

题意:任务规定,一个酸奶制造厂,在n个星期内,分别要向外提供y[i]unit的酸奶。已知这个制造厂第i周制造每unit酸奶的费用为c[i],储存室储存每1unit酸奶1星期的费用为s。问要完成这个任务的最小费用是多少。

看似是动态规划,实际上贪心处理一遍原数组即可。
对于每一天,考虑是当天生产的代价高,还是使用昨天生产的代价+储存代价高,选择一个代价低的,更新为当天的代价。

  • 这样考虑实际上是考虑了相隔很远的情况。
    假如第一天的代价是1,最后一天的代价是INF,处理以后,最后一天的代价也会变得很小。

  • 这样处理之后原代价并不会发生变化
    储存代价是5
    第一天89 400
    第二天97 300
    第二天会被更新为->94
    因此这样算的代价是89*400+(5+89)*300`
    代表的意思就是
    (89)*700+(5)*300`生产700,存放300

long long ans=0;      for(int i=1;i<n;i++)          c[i]=min(c[i-1]+s,c[i]);      for(int i=0;i<n;i++)          ans+=c[i]*y[i];      printf("%lld\n",ans);
0 0