2018-07-22题解

2018 07 22


T1

Description
今年的英仙座流星雨非常的特别。有 N 颗星星同时从天空中落下。
少女拥有一个神奇的魔法,每一次可以从正在下落的星星中选择一颗令其固定在天空中,不再下落。但是,少女的魔法并不是完美的,在每一次选择的时候,都会有一颗星星不能被选中,否则魔法就会失效了。如果魔法成功的话,经过 N 次的选择后,天空中就会出现一条星星连成的银线(虽然是个折线)。
少女知道,在这 N 次选择里,每颗星星都会有且仅有一次不能被选中。她已经通过万能的占卜师·东条希的占卜知道了每次选择中哪一颗星星不能被选中。少女想知道,通过每次选择不同的星星,她一共可以在星空画出多少条不同的银线?

Input
输入的第一行为一个正整数N,表示一共有N颗星星,编号为1到N;第二行为N个正整数Ci,1<=Ci<=N,表示每i次不能选择的星星编号为Ci。
对于30%的数据,n<=10。对于50%的数据,n<=1e3。对于70%的数据,n<=1e5。对于100%的数据,n<=1e7。

Output
输出仅包含一个整数,表示可以画出的不同线的条数。由于这个数可能会非常大,你需要将这个答案对20180315取模后输出。

Hint
这是一道数学题
题意中规定 每颗星星都会有且仅有一次不能被选中在某次选择中不能选
我们可以想到\{ C_n \}的顺序是没有意义的(\{C_n\}定义见输入描述,感性理解一下就好了)
所以我们可以认为它就是1, 2, 3, 4...n
那么这题就转化为:有多少n的排列,满足a_i \neq i
错排
所以这题就是求n的错排.
我参考了一位大佬的博客,讲的很不错了

Code

#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define siz 10000010
#define mod 20180315
using namespace std;
int n;
long long a[siz];
int main() {

    scanf("%d",&n);
    a[1] = 0, a[2] = 1;
    for(int i = 3; i <=n; ++i)
      a[i] = ( ( ( a[i - 1] + a[i - 2] ) % mod ) * (i - 1) ) % mod;
    printf("%lld",a[n]);
    return 0;
}

T2

Description
海未面前现在有n个靶子。按照绘里的指示,海未需要把这n个靶子全部射穿才行。
一开始,海未的精力为m,力度为a。每射穿一个靶子,海未对弓的熟练度就会上升,此时力度会增加b。
每个靶子都有一个单独的耐久度d[i],每次受到海未的攻击,靶子的耐久度都会减少海未当前的力度的值。当靶子的耐久度为0或0以下时,靶子被破坏。但是,如果海未在一次射箭后并没有射穿这个靶子,海未的精力会减少c[i]。如果海未通过一次射箭破坏了靶子,她的精力不会受到影响。
海未可以自由地选择射靶子的顺序。请问,海未是否能够通过合理地安排射靶子的顺序,使得她能够将这些靶子全部射穿?如果能,她完成任务后最多能省下多少精力?如果不能,她最多可以射穿多少个靶子?

Input
输入的第一行为四个正整数 n,m,a,b。
接下来 n 行,每行两个正整数 c[i],d[i]。
对于 30%的数据,n<=6。
对于 50%的数据,n<=9。
对于 70%的数据,n<=14。
对于 100%的数据,n<=21;1<=a,b,c,d<=32767。

Output
输出的第一行仅包含一个字符串。请回答海未酱是否能完成全部射穿靶子的任务。如果可以
完成,输出“Yes”。如果不能完成,输出“No” 。(两者均不包括引号)
第二行仅包含一个正整数。若第一行为“Yes”,则你应输出所剩的最多精力值;若第一行为
“No”,则你应输出最多能射穿的靶子数

Hint
状压dp
应该是比较简单的一道状压了,然而考试的时候没打出来….打了个全排列凑数

Code

全排列

#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define siz 30
#define mod 
using namespace std;
int n, m, a, b, ans1=0, ans2=-1;
int order[siz], c[siz], d[siz];
bool flag;
int main() {

    scanf("%d%d%d%d",&n,&m,&a,&b);
    for(int i = 1; i <= n; ++i) scanf("%d%d",&c[i],&d[i]);
    for(int i = 0; i < n; ++i) order[i] = i + 1;
    do {
        int ta = a, tm = m;
        for(int i = 0; i < n; ++i) {
            int td = d[ order[i] ];
            while(td > 0) {
                td -= ta;
                if(td <= 0) break;
                tm -= c[ order[i] ];
            }
            if(tm <= 0) {
                if(i > ans2) ans2 = i;
                break;
            } else ta += b;
        }
        if(tm > ans1) flag = 1, ans1 = tm; 
    } while(next_permutation(order,order+n));

    if(flag) printf("Yes\n%d",ans1);
    else printf("No\n%d",ans2);
    return 0;
}

T3

Description
今年全国大会的总决赛比赛方式与之前有些出入。并不是比谁射靶子射的准,而是射气球。
当然啦,还是要射的准的。
参赛的选手站在三维比赛场地的正中央,坐标为(0,0,0)的位置。主办方在场地中放置了 N
个气球。这些气球都通过特殊的方式固定好了,因此并不会乱动。
每位选手可以朝着某一个方向射出唯一的一支箭。击中最多的气球的选手将获得大赛的冠军。
也就是说,这一次是一场同时对技术和头脑的考验。
海未已经得知了各个气球的位置和半径。她想知道,如果朝着某方向射箭,她能够射到最多
的气球,这个最多的数量是多少?
为了简化模型,我们假设海未射出的箭被东条希加了一个神奇的 buff。她射出的箭的轨迹将
保持为一条射线,也就是说不受空气阻力,射中气球的阻力,甚至重力等影响。

Input
第一行一个正整数 n。
接下来 n 行,每行四个非负整数 xi,yi,zi,ri,表示气球的坐标(xi,yi,zi)和半径 ri

Output
输出仅含有一个整数,表示最多能击中的气球数。

Hint
这题就比较皮了

随机

  • 首先我们保证能击中一个气球,所以我们随机选一个气球
  • 然后我们在这个气球能覆盖的横坐标段中随机选一个x
  • 然后在这个气球横坐标为x的那一个圆环上随机选一个y
  • 然后算出z
  • 这样我们连接原点和我们随机选出的(x,y,z),得到得到一条直线
  • 然后我们 O(n) 判断还有那些球会被直线穿过,即它的球心到直线距离小于半径
  • 至于三维坐标系中点到线距离,其实用一下向量思想就好了

Code



posted @ 2018-07-22 16:20  Nepenthe  阅读(181)  评论(0)    收藏  举报


删边加边,浮生建模