2019.8.1效实模拟赛题解

· · 个人记录

话不多说先上题

1、判断素数个数

这是一道十分简单的题目。
(我是不会告诉你们输入的两个端点是无序的)
如此简单的题目就上代码吧

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdio>

using namespace std;

int a[110000];

int main()
{
//    freopen("prime.in","r",stdin);
//    freopen("prime.out","w",stdout);
    int n,m;
    cin>>n>>m;
    if (m<=n) swap(m,n);
    memset(a,0,sizeof(a));
    a[1]=1;
    for (int i=2;i<=317;i++)
        for (int j=2;j<=100000/i;j++)
        {
            a[i*j]=1;
        }
    int tmp=0;
    for (int i=n;i<=m;i++)
    {
        tmp+=1-a[i];
    }
    cout<<tmp<<endl;
    return 0;
}

2、火车调度序列统计

这也是一道十分简单的题目,但是我们需要有一双明亮的眼睛来发现这其实是catalan数(像我就是在比赛的时候受到了大佬的提示
catalan数的计算公式如下: **\frac{1}{n+1}

但是这道题要用高精度,但是我忘了高精度除法,so看代码 ```cpp #include <iostream> #include <algorithm> #include <cmath> #include <cstring> #include <cstdio> using namespace std; int a[1010]; int gcd(int x,int y) { int a,b,c; a=x,b=y,c=a%b; while (c!=0) { a=b,b=c,c=a%b; } return b; } int p,ans[3000]; int cheng(int x) { int k=0; for (int i=1;i<=p;i++) { k+=ans[i]*x; ans[i]=k%10; k/=10; } while (k>0) { p++; ans[p]=k%10; k/=10; } return 0; } int main() { freopen("stack.in","r",stdin); freopen("stack.out","w",stdout); int n; cin>>n; for (int i=1;i<=n;i++) a[i]=n+i; int x,j,y; for (int i=2;i<=n+1;i++) { x=i;j=1; while (x>1) { y=gcd(x,a[j]); a[j]/=y; x/=y; j++; } } p=1;ans[1]=1; for (int i=1;i<=n;i++) cheng(a[i]); for (int i=p;i>=1;i--) cout<<ans[i]; cout<<endl; return 0; } ``` 下面要总结一下catalan数的几个常用使用处: 1、括号匹配问题(n对括号有多少种匹配方式) 2、进栈出栈问题(一个栈(无穷大)的进栈序列为1,2,3,……,n,有多少个不同的出栈序列) 3、二叉树的种类问题(n个节点构成的二叉树,共有多少种情形) 4、凸多边形分割问题(求一个凸多边形区域划分成三角形区域的方法数) 5、集合划分问题(对于集合{1,2,3...2n}的不交叉划分的数目为多少) 6、连线不相交问题(在圆上有2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数) 7、门票找钱问题 有2n个人排成一行进入剧场。入场费5元。其中只有n个人有一张5元钞票,另外n人只有10元钞票,剧院无其它钞票,问有多少中方法使得只要有10元的人买票,售票处就有5元的钞票找零 --- ## 3、[贪心的小精灵](http://www.nbxiaoshi.net:8011/problem/5002) 很基础的一道动态规划的题目,和数字三角形很像(不同点是此题要过一个规定的点) 那么我们就按数字三角形的思想方法来解决这个问题:将到了这个点以后就将一定无法到达的点(在这个点下方的,因为我是自下而上动规的)清为-$\infty$。然后就可以做一个基本动规了。 代码如下: ```cpp #include <iostream> #include <algorithm> #include <cmath> #include <cstring> #include <cstdio> using namespace std; int a[110][110],f[110][110]; int main() { // freopen("gift.in","r",stdin); // freopen("gift.out","w",stdout); int n; cin>>n; for (int i=1;i<=n;i++) for (int j=1;j<=i;j++) cin>>a[i][j]; int x,y,y1; cin>>x>>y; y1=y; for (int i=x;i<=n;i++) { for (int j=1;j<=y-1;j++) a[i][j]=-2000000; for (int j=y1+1;j<=i;j++) a[i][j]=-2000000; y1++; } memset(f,0,sizeof(f)); for (int i=1;i<=n;i++) f[n][i]=a[n][i]; for (int i=n-1;i>=1;i--) { for (int j=1;j<=i;j++) f[i][j]=a[i][j]+max(f[i+1][j],f[i+1][j+1]); } cout<<f[1][1]<<endl; return 0; } ``` --- ## 4、[取火柴游戏](http://www.nbxiaoshi.net:8011/problem/5003) 这是一个博弈论的经典题目。 又称Nim取石子游戏(^_^) 这道题目存在必胜态和必败态: 首先,我们可以确定:如果当前状态为必胜态的话,一定有方法将其转化为必败态(也就是一定会让对手必败)。 其次,如果当前状态为必胜态的话,无论如何操作都会使状态转化为必胜态(也就是对手在必败态的情况下一定会使你重新变回必胜态)。 所以我们要思考就是如何将一个必胜态转化为一个必败态。 我们设: x=a[1]^a[2]^a[3]^……^a[n] 若x=0,则当前状态属于必败态。 否则,我们要将一个必胜态转化为必败态,方法如下: 我们可以确定:存在k使 a[k]>=a[k]^x (x的最高位是来自于a中的,所以我们可以确定一定存在k) 将a[k]替换为a[k]^x,则可以得到: a[1]^a[2]^……^a[k]^x^……^a[n]=x^x=0 得到了必败态 那么我们就知道了a[k]-a[k]^a[n]是一个可行的操作。 下面是代码 ```cpp #include <iostream> #include <algorithm> #include <cmath> #include <cstring> #include <cstdio> using namespace std; int a[20],x[500001]; int main() { // freopen("stick.in","r",stdin); // freopen("stick.out","w",stdout); int n,xorh=0; cin>>n; for (int i=1;i<=n;i++) { scanf("%d",&x[i]); xorh=x[i]^xorh; } if (xorh==0) { cout<<"lose"<<endl; return 0; } int answei,anszhi; for (int i=1;i<=n;i++) { if (x[i]>=(x[i]^xorh)) { answei=i; anszhi=x[i]-(x[i]^xorh); x[i]-=anszhi; break; } } cout<<anszhi<<" "<<answei<<endl; for (int i=1;i<=n;i++) cout<<x[i]<<" "; cout<<endl; return 0; } ``` --- ## 5、[十二号诛杀者](http://www.nbxiaoshi.net:8011/problem/40) 一个图论中的题目 用中间节点、线段树优化和最短路算法来实现,代码正在赶来的途中……