标签 模拟 下的文章

url: http://oj.ecustacm.cn/problem.php?id=1369

tag:
模拟

思路:
求字节的二进制表示,其实就是求每个数的补码。对于正数来说,补码就是原码。对于负数来说,先是对原码求反码然后再加1.对于-128来说比较特殊,补码是10000000,通过正常的求法求不出,所以需要特殊判断。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
int num[10];

void resoult(int a)
{
    int j = 8;
    while(a)
    {
        num[j --] = a % 2;
        a /= 2;
    }
}
void inverse()
{
    for (int i = 2; i <= 8; i ++)
    {
        if (num[i] == 0) num[i] = 1;
        else num[i] = 0;
    }
    num[8] += 1;
    for (int i = 8; i >= 3; i --)
    {
        num[i - 1] += num[i] / 2;
        num[i] %= 2;
    }
}
void binary(int a)
{
    if (a == -128)
    {
        cout << "1 " << endl;
        return;
    }
    memset(num, 0, sizeof num);
    if (a >= 0)
    {
        num[1] = 0;
        resoult(a);
    }
    else
    {
        num[1] = 1;
        resoult(abs(a));
        inverse();
    }
}
void print()
{
    for (int i = 1; i <= 8; i ++)
    {
        if (num[i]) cout << 1;
        else cout << ' ';
    }
}
int main()
{
    for (int i = 0; i < 10; i ++)
    {
        for (int j = 0; j < 16; j ++)
        {
            int a, b;
            cin >> a >> b;
            binary(a);
            print();
            binary(b);
            print();
            cout << endl;
        }
        cout << endl;
    }
    return 0;
}

简洁版:

#include <iostream>
#include<cstring>
using namespace std;
int num[10];
void print()
{
    
    for(int i=1;i<=8;i++) printf("%c",num[i]==1?"1":" ");
}
int main()
{
    
    int a,b;
    for(int i=1;i<=10;i++)
    {
    
        for(int j=1;j<=16;j++)
        {
    
            cin>>a>>b;
            memset(num,0,sizeof(num ));
            for(int k =8;k>=1;i--) num[k]&=a,a>>=1;
            print();
             memset(num,0,sizeof(num ));
            for(int k =8;k>=1;k--) num[k]&=b,b>>=1;
            print();
            cout<<endl;
        }
        cout<<endl;
    }
    return 0;
}

结果:

     1
     1
     1    1
111111111111
     1    1
     1    1
     1    1
     1    1
     1    1
    1     1
    1     1
   1      1   1
   1      1   1
  1        1111
11

   1     1
   1     1
  1   1  1   1
 1111111 111111
 1    1 1    1
 1    11     1
 1    1      1
 1    1 1    1
 111111  11  1
 1    1   1  1
 1    1      1
 1    1      1
 1    1      1
 111111      1
 1    1   1 1
           1

     1
     1
     1
     1    1
111111111111
     1    1
     1    1
     1    1
     1    1
     1    1
    1     1
    1     1
   1      1   1
   1      1   1
  1        1111
11

        1

 1      1
 1
  11    1
  11
   1   1    1
       1111111
      1     1
    1    1 1
   1     1
  1      1
111      1
  1     1 1
  1     1 1
  1    1   1
  1   1     1
  1  1      111
  1 1        1

     1
      11
       1
             1
111111111111111
     1
     1     1
     11111111
     1     1
     1     1
     1     1
    1      1
    1      1
   1       1
  1     1 1
 1       1

   1     1
   1 1   1  1
  11111 111111
 1  1  1  1
     1 1   1
       1
  11111111111
       1
111111111111111
         1
         1 1
  11111111111
    1    1
     1   1
       1 1
        1


           1
  11111111111
       1
       1
       1
       1     1
111111111111111
       1
       1
       1
       1
       1
       1
       1
     1 1
      1

      1
      1
     1111111
    1     1
   11    1
  1  1 11
  1  1 1
      1 1
      1
    11  1
    11
 111   1111111
      1     1
    11     1
   1  1   1
  1    111
       1
    111
 111

       1
       1
       1
    1  1  1
    1  1   1
   1   1    11
   1   1     1
  1    1   1
 1     1   1
       1  1
       1 1
        1

       1
      1
    11
 111




     1111111
   11      11
  11        11
  111       11
          111
        111
        11
        1



       11
       1
      1111
       11
       1


答案:

#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;
int main()
{
    printf("%.0f", pow(9, 9));
    return 0;
}

url: https://www.luogu.com.cn/problem/P1488

tag:
博弈论,模拟

思路:我觉得比起博弈论,更像是模拟题。这道题先是判断黑色三角形的位置,通过判断是不是有两条边为多边形的边界,如果是,说明先手可以直接切。如果不是,就继续判断n-5的奇偶性,n-5是三角形的个数,表示切了n-5个,这个数是因为一种特殊情况,当场上只有三个三角形的时候,且黑色不是在外层,这个时候如果先手切了一个,那么后手必胜,反之后手切了一个则先手必胜。一共有n-2个三角形,除去最后3个,一共是n-5个,表示进行了n-5次操作,如果为偶数次,说明第n-5次操作是后手,那么第n-4次就是先手,后手必胜,反之如果是奇数次,说是第n-5次操作时先手,那么第n-4次就是后手,先手必胜。总结一下就是当n-5为偶数后手胜,为奇数先手胜。

代码:

#include <iostream>
#include <cmath>
using namespace std;
int n, x, y, z;
int main()
{
    cin >> n;
    cin >> x >> y >> z;
    int cnt = 0;
    if (abs(x - y) == 1 || abs(x - y) == n - 1) cnt ++;
    if (abs(x - z) == 1 || abs(x - z) == n - 1) cnt ++;
    if (abs(y - z) == 1 || abs(y - z) == n - 1) cnt ++;
    if (cnt == 2)
    {
        cout << "JMcat Win";
        return 0;
    }
    if ((n - 5) % 2) cout << "JMcat Win";
    else cout << "PZ Win";
    return 0;
}

url: https://www.luogu.com.cn/problem/P4343

tag:
二分,模拟

思路:
思路比较简单,根据题目可以知道当n越小时切出来的题目数量越多,根据这个来二分。分别二分出一个最小值和一个最大值。这道题是细节比较 恶心(bushi 多,需要注意的点比较多。第一个是二分的范围,题目只有一个xi的范围是1e-9到1e9,经测试,r开到1e9范围比较小,看了题解之后发现需要开到1e18.然后这里就有一个问题,因为超过了1e9所以变量不能放到main()函数中,只能放到外面当全局变量。然后如果是mid要用long long类型,记得check函数的函数签名中变量的类型也要是long long。第二个细节是l要从1开始,不能从0开始。第三个细节是,题目没有保证说如果其中一个答案比如最小值存在,另外一个答案就会存在,所以对于最小值和最大值都要进行验证。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
long long n, k, l ,r;
long long p[N];

long long check (long long x)
{
    long long sum = 0, cnt = 0;
    for (int i = 0; i < n; i ++)
    {
        if (p[i] > 0) sum += p[i];
        else sum = max((long long)0, sum + p[i]);
        if (sum >= x)
        {
            sum = 0;
            cnt ++;
        }
    }
    return cnt;
}
int main()
{
    scanf("%lld%lld", &n, &k);
    for (int i = 0; i < n; i ++) scanf("%lld", &p[i]);
    l = 1, r = 1e18;

    while (l < r)
    {
        long long mid = (l + r) >> 1;
        if (check(mid) <= k) r = mid;
        else l = mid + 1;
    }
    long long tmp;
    if (check(l) != k)
    {
        cout << -1 ;
        return 0;
    }
    else tmp = l;
    l = 1, r = 1e18;
    while (l < r)
    {
        long long mid = (l + r + 1) >> 1;
        if (check(mid) >= k) l = mid;
        else r = mid - 1;
    }
    if (check(l) != k)
    {
        cout << -1 ;
        return 0;
    }
    else cout << tmp << ' ' << l;
    return 0;
}

url: https://www.luogu.com.cn/problem/B3738

tag:
模拟,数学

思路:
数据范围比较小,可以用模拟的方式来通过这道题。比较难的部分应该是蛇形填充。这里可以先用一个数组来存放四个前进的方向。之后每次都判断一下前进之后的位置符不符合要求(不越界且当前位置没有被填充过),如果符合要求则前进,然后将数字放进矩阵,否则就换一个方向。

代码:

#include <iostream>
using namespace std;
int n, x, y;
const int N = 22;
int p[410], dp[N][N], d;
int dir[4][2] = {
        {0, 1},
        {1, 0},
        {0, -1},
        {-1, 0},
};
bool is_pr(int x)
{
    for (int i = 2; i * i <= x; i ++)
    {
        if (x % i == 0) return false;
    }
    return true;
}
int main()
{
    cin >> n >> x >> y;
    int k = 2;
    for (int i = 1; i <= n * n; i ++)
    {
        while (!is_pr(k++));
        p[i] = --k;
        k ++;
    }
    int nx = 0, ny = 0;
    dp[0][0] = p[1];
    for (int i = 2; i <= n * n; i ++)
    {
        int tmpx, tmpy;
        tmpx = nx + dir[d][0], tmpy = ny + dir[d][1];
        if (tmpx >= n || tmpx < 0 || tmpy >= n || tmpy < 0 || dp[tmpx][tmpy])
        {
            d = (d + 1) % 4;
            tmpx = nx + dir[d][0], tmpy = ny + dir[d][1];
        }
        nx = tmpx, ny = tmpy;
        dp[nx][ny] = p[i];
    }
    cout << dp[x - 1][y  - 1] << endl;
    return 0;
}

url : https://www.luogu.com.cn/problem/P2694

tag:
模拟

思路:
为了可以接到所有的金币,所以我们可以采取一个贪心的策略,每次都先去接高度距离自己最近的一个金币,之后判断在这个过程中是否存在接不到的情况,如果有就说明接不到所有的金币,否则就是可以接到所有的金币。
为了采取贪心的策略,我们需要对所有的金币按照高度排序。然后需要维护一个全局的掉落高度 ey 和自己的位置 fx ,之后按照高度遍历每一个金币,判断,当我走到这个金币的时候金币到我的高度,如果大于等于0则说明可以接到,否则接不到。如果可以接到,则更新一下ey和fx。
关于如何排序,可以利用pair的特性,即先按照first排序如果一样再按照second排序,来排。所以我们可以用pair来存每一个金币的位置,且将高度放到first。
关于如何判断,因为题目有给一个速度都是1,所以移动的距离(用绝对值表示)就是这一段时间,即从原来我的位置到要接的那个金币下面的时间,金币下降的高度。所以先让 ey += abs(fx - dp[i].second),之后再判断 dp[i].first - ey 的大小。如果大于0就可以接到,小于零就break掉。
当大于0时,为了可以接到,所以必须让金币的高度为0,因此就还要等一段时间,这段时间fx不会更新,但是ey需要再加上 dp[i].first - ey, 表示在等待的过程中全局的下降距离增加的距离。
ps:如果速度不为1可能反而会好理解一点。

代码:

#include <iostream>  
#include <algorithm>  
using namespace std;  
typedef pair<int, int> PII;  
PII dp[52];  
int main()  
{  
    int g;  
    cin >> g;  
    while(g--)  
    {  
        int n;  
        bool flag = true;  
        cin >> n;  
        int fx = 0, ey = 0;  
        for (int i = 0; i < n; i ++)  
        {  
            cin >> dp[i].second >> dp[i].first;  
        }  
        sort(dp, dp + n);  
        for (int i = 0; i < n; i ++)  
        {  
            ey += abs(fx - dp[i].second);  
            if (dp[i].first - ey >= 0)  
            {  
                ey += dp[i].first - ey;  
                fx = dp[i].second;  
            }  
            else  
            {  
                flag = false;  
                cout << "Notabletocatch\n";  
                break;  
            }  
        }  
        if (flag) cout << "Abletocatch\n";  
    }  
    return 0;  
}