Test 7 for NOIP

来源:互联网 发布:知乎如何添加好友 编辑:程序博客网 时间:2024/05/29 15:24

头大

这个暑假完就要去搞NOIP了。。。

暑假55天也就20次测试。。。为防万一我还是每次测试玩都写个总结。。


曾老又放出了大招,又甩了一套2016真题。(不过貌似很久以前也没有做过?)
。。。结果还行,最后只拿了100分。。最后上了225还是可以。

感谢博主http://blog.csdn.net/clove_unique/article/details/53427248提供的代码。

Day2(误)(100/300)

T1 组合数问题【NOIP2016提高组】(100/100)

题目背景
NOIP2016 提高组 Day2 T1

题目描述
组合数 表示的是从 n 个物品中选出 m 个物品的方案数。举个例子,从 (1,2,3) 三个物品中选择两个物品可以有 (1,2),(1,3),(2,3) 这三种选择方法。根据组合数的定义,我们可以给出计算组合数 的一般公式:
C(m)(n)=n!/(m!(n-m)!)
其中 n!=1×2×…×n 。

小葱想知道如果给定 n,m 和 k,对于所有的 0≤i≤n,0≤j≤min(i,m) 有多少对 (i,j) 满足C(j)(i)是 k 的倍数。

输入格式
第一行有两个整数 t,k,其中 t 代表该测试点总共有多少组测试数据,k 的意义见【问题描述】。

接下来 t 行每行两个整数 n,m,其中 n,m 的意义见【问题描述】。

输出格式
输出 t 行,每行一个整数代表所有的 0≤i≤n,0≤j≤min(i,m) 中有多少对 (i,j) 满足 是 k 的倍数。

样例数据 1
输入  [复制]

1 2
3 3
输出

1
样例数据 2
输入  [复制]

2 5
4 5
6 7
输出

0
7
备注
【样例1说明】
在所有可能的情况中,只有C(1)(2)是 2 的倍数。

这道题只要会用几天前学的组合数的动归就行,再加个动鬼记录答案即可。

MY.CPP

#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<string>#include<algorithm>using namespace std;int t,k,c[4000][4000],ans[4000][4000];int n,m;int main(){    cin >> t >> k;    for(int i=1;i<=2005;i++)c[i][0]=c[i][i]=1;    for(int i=2;i<=2005;i++)      for(int j=1;j<=min(i,2005);j++)      {        c[i][j] = (c[i-1][j] + c[i-1][j-1])%k;        if(!c[i][j])    ans[i][j] = 1;      }    for(int i=1;i<=2005;i++)      for(int j=1;j<=2005;j++)        ans[i][j] = ans[i][j]+ans[i-1][j]+ans[i][j-1]-ans[i-1][j-1];    while(t--)    {        cin >> n >> m;        cout << ans[n][m] << endl;    }}

T2 蚯蚓【NOIP2016提高组】(0/100)

题目背景
NOIP2016 提高组 Day2 T2

题目描述
本题中,我们将用符号 表示对 c 向下取整,例如:

蛐蛐国最近蚯蚓成灾了!隔壁跳蚤国的跳蚤也拿蚯蚓们没办法,蛐蛐国王只好去请神刀手来帮他们消灭蚯蚓。

蛐蛐国里现在共有 n 只蚯蚓(n为正整数)。每只蚯蚓拥有长度,我们设第 i 只蚯蚓的长度为 ai (i=1,2,… ,n),并保证所有的长度都是非负整数(即:可能存在长度为0的蚯蚓)。

每一秒,神刀手会在所有的蚯蚓中,准确地找到最长的那一只(如有多个则任选一个)将其切成两半。神刀手切开蚯蚓的位置由常数 p(是满足 0<p<1 的有理数)决定,设这只蚯蚓长度为 x ,神刀手会将其切成两只长度分别为 的蚯蚓。特殊地,如果这两个数的其中一个等于 0 ,则这个长度为 0 的蚯蚓也会被保留。此外,除了刚刚产生的两只新蚯蚓,其余蚯蚓的长度都会增加 q(是一个非负整常数)。

蛐蛐国王知道这样不是长久之计,因为蚯蚓不仅会越来越多,还会越来越长。蛐蛐国王决定求助于一位有着洪荒之力的神秘人物,但是救兵还需要 m 秒才能到来……(m为非负整数)

蛐蛐国王希望知道这 m 秒内的战况。具体来说,他希望知道:

m 秒内,每一秒被切断的蚯蚓被切断前的长度(有 m 个数);
m 秒后,所有蚯蚓的长度(有 n+m 个数)。
蛐蛐国王当然知道怎么做啦!但是他想考考你……

输入格式
第一行包含六个整数 n,m,q,u,v,t,其中:n,m,q 的意义见【问题描述】;u,v,t 均为正整数;你需要自己计算p=u/v(保证 0 < u < v);t 是输出参数,其含义将会在【输出格式】中解释。

第二行包含 n 个非负整数,为 a1,a2,… ,an,即初始时 n 只蚯蚓的长度。

同一行中相邻的两个数之间,恰好用一个空格隔开。

保证 1≤n≤105,0≤m≤7×106,0<u<v≤109,0≤q≤200,1≤t≤71,0≤ai≤108。

输出格式
第一行输出m/t个整数,按时间顺序,依次输出第 t 秒,第 2t 秒,第 3t 秒,……被切断蚯蚓(在被切断前)的长度。

第二行输出n+m/t个整数,输出 m 秒后蚯蚓的长度;需要按从大到小的顺序,依次输出排名第 t,第 2t,第 3t,……的长度。

同一行中相邻的两个数之间,恰好用一个空格隔开。即使某一行没有任何数需要输出,你也应输出一个空行。

请阅读样例来更好地理解这个格式。

样例数据 1
输入  [复制]

3 7 1 1 3 1
3 3 2
输出

3 4 4 4 5 5 6
6 6 6 5 5 4 4 3 2 2
样例数据 2
输入  [复制]

3 7 1 1 3 2
3 3 2
输出

4 4 5
6 5 4 3 2
样例数据 3
输入  [复制]

3 7 1 1 3 9
3 3 2
输出

2
备注
【样例1说明】
在神刀手到来前:3 只蚯蚓的长度为 3,3,2。

【样例2说明】
这个数据中只有 t=2 与上个数据不同。只需在每行都改为每两个数输出一个数即可。
虽然第一行最后有一个 6 没有被输出,但是第二行仍然要重新从第二个数再开始输出。

【样例3说明】
这个数据中只有 t=9 与上个数据不同。
注意第一行没有数要输出,但也要输出一个空行。

1 秒后:一只长度为 3 的蚯蚓被切成了两只长度分别为 1 和 2 的蚯蚓,其余蚯蚓的长度增加了 1 。最终 4 只蚯蚓的长度分别为 (1,2),4,3 。括号表示这个位置刚刚有一只蚯蚓被切断。
2 秒后:一只长度为 4 的蚯蚓被切成了 1 和 3 。5 只蚯蚓的长度分别为:2,3,(1,3),4 。
3 秒后:一只长度为 4 的蚯蚓被切断。6 只蚯蚓的长度分别为:3,4,2,4,(1,3)。
4 秒后:一只长度为 4 的蚯蚓被切断。7 只蚯蚓的长度分别为:4,(1,3),3,5,2,4。
5 秒后:一只长度为 5 的蚯蚓被切断。8 只蚯蚓的长度分别为:5,2,4,4,(1,4),3,5。
6秒后:一只长度为5的蚯蚓被切断。9只蚯蚓的长度分别为:(1,4),3,5,5,2,5,4,6。
7 秒后:一只长度为 6 的蚯蚓被切断。10只蚯蚓的长度分别为:2,5,4,6,6,3,6,5,(2,4)。
所以,7 秒内被切断的蚯蚓的长度依次为 3,4,4,4,5,5,6。7 秒后,所有蚯蚓长度从大到小排序为 6,6,6,5,5,4,4,3,2,2。

【数据规模与约定】
测试点 1~3 满足 m=0。
测试点 4~7 满足 n,m≤1,000。
测试点 8~14 满足 q=0,其中测试点 8~9 还满足 m≤105。
测试点 15~18 满足 m≤3×105。
测试点 19~20 没有特殊的约定,参见原始的数据范围。
测试点 1~12,15~16 还满足 v≤2 ,这意味着 u,v 的唯一可能的取值是 u=1,v=2,即 p=0.5。这可能会对解决问题有特殊的帮助。

【数据规模与约定】
对于 30% 的数据,N,M≤50。
对于 60% 的数据,N,M≤100。
对于 80% 的数据,N≤2000;M≤10000。
对于 100% 的数据,1≤N≤105;1≤M≤2×105;1≤Ai,Bi≤N,Ai≠Bi,0≤Ci<M。

队列没有整好,在priority_queue的操作上搞了半天没搞出来GG。。后来发现每次切得的蚯蚓一定比它被分到的当前队列的所有元素小,所以不必再去维护。三个常规数组就能搞定。

STD.CPP

#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<string>#include<algorithm>#include<queue>#include<vector>using namespace std;#define inf 2100000000#define N 100005int n,m,t,x,q,add,a[N];double u,v,p;int d[4][N*100],l[4],r[4];int cmp(int a,int b){    return a>b;}int Max(){    int a=-inf,b=-inf,c=-inf,ans=1;    if (l[1]<r[1]) a=d[1][l[1]];    if (l[2]<r[2]) b=d[2][l[2]];    if (l[3]<r[3]) c=d[3][l[3]];    if (a<b) a=b,ans=2;    if (a<c) a=c,ans=3;    return ans;}int main(){    cin>>n>>m>>q>>u>>v>>t;p=u/v;    for (int i=1;i<=n;++i) cin >> a[i];    sort(a+1,a+n+1,cmp);    for (int i=1;i<=n;++i) d[1][r[1]++]=a[i];    for (int i=1;i<=m;++i)    {        int k=Max();        int now=d[k][l[k]++]+add;        if (i%t==0)        {            if (i>t) putchar(' ');            cout << now;        }        int nxt1=floor(p*(double)now),nxt2=now-floor(p*(double)now);        add+=q;        d[2][r[2]++]=nxt1-add,d[3][r[3]++]=nxt2-add;    }    cout << endl;    for (int i=1;i<=n+m;++i)    {        int k=Max();        int now=d[k][l[k]++]+add;        if (i%t==0)        {            if (i>t) putchar(' ');            cout << now;        }    }}

T3 愤怒的小鸟【NOIP2016提高组】(0/100)

题目背景
NOIP2016 提高组 Day2 T3

题目描述
Kiana 最近沉迷于一款神奇的游戏无法自拔。简单来说,这款游戏是在一个平面上进行的。

有一架弹弓位于 (0,0) 处,每次 Kiana 可以用它向第一象限发射一只红色的小鸟,小鸟们的飞行轨迹均为形如 y=ax2+bx 的曲线,其中 a,b 是 Kiana 指定的参数,且必须满足 a<0。

当小鸟落回地面(即x轴)时,它就会瞬间消失。

在游戏的某个关卡里,平面的第一象限中有 n 只绿色的小猪,其中第 i 只小猪所在的坐标为 (xi,yi) 。

如果某只小鸟的飞行轨迹经过了(xi,yi),那么第 i 只小猪就会被消灭掉,同时小鸟将会沿着原先的轨迹继续飞行;

如果一只小鸟的飞行轨迹没有经过(xi,yi),那么这只小鸟飞行的全过程就不会对第 i 只小猪产生任何影响。

例如,若两只小猪分别位于 (1,3) 和 (3,3) ,Kiana 可以选择发射一只飞行轨迹为 y=-x2+4x 的小鸟,这样两只小猪就会被这只小鸟一起消灭。

而这个游戏的目的,就是通过发射小鸟消灭所有的小猪。

这款神奇游戏的每个关卡对 Kiana 来说都很难,所以 Kiana 还输入了一些神秘的指令,使得自己能更轻松地完成这个游戏。这些指令将在【输入格式】中详述。

假设这款游戏一共有 T 个关卡,现在 Kiana 想知道,对于每一个关卡,至少需要发射多少只小鸟才能消灭所有的小猪。由于她不会算,所以希望由你告诉她。

输入格式
下面依次输入这 T 个关卡的信息。每个关卡第一行包含两个非负整数 n,m ,分别表示该关卡中的小猪数量和 Kiana 输入的神秘指令类型。接下来的 n 行中,第 i 行包含两个正实数 xi,yi ,表示第 i 只小猪坐标为 (xi,yi)。数据保证同一个关卡中不存在两只坐标完全相同的小猪。

如果 m=0,表示 Kiana 输入了一个没有任何作用的指令。
如果 m=1 ,则这个关卡将会满足:至多用 只小鸟即可消灭所有小猪。
如果 m=2 ,则这个关卡将会满足:一定存在一种最优解,其中有一只小鸟消灭了至少 只小猪。
保证 1≤n≤18,0≤m≤2,0<xi,yi<10,输入中的实数均保留到小数点后两位。
上文中,符号 分别表示对 c 向上取整和向下取整,例如:

输出格式
对每个关卡依次输出一行答案。
输出的每一行包含一个正整数,表示相应的关卡中,消灭所有小猪最少需要的小鸟数量。

样例数据 1
输入  [复制]

2
2 0
1.00 3.00
3.00 3.00
5 2
1.00 5.00
2.00 8.00
3.00 9.00
4.00 8.00
5.00 5.00
输出

1
1
样例数据 2
输入  [复制]

3
2 0
1.41 2.00
1.73 3.00
3 0
1.11 1.41
2.34 1.79
2.98 1.49
5 0
2.72 2.72
2.72 3.14
3.14 2.72
3.14 3.14
5.00 5.00
输出

2
2
3
样例数据 3
输入  [复制]

1
10 0
7.16 6.28
2.02 0.38
8.33 7.78
7.68 2.09
7.46 7.86
5.77 7.44
8.24 6.72
4.42 5.11
5.42 7.79
8.15 4.99
输出

6
备注
【样例1说明】
这组数据中一共有两个关卡。

第一个关卡与【问题描述】中的情形相同,2 只小猪分别位于 (1.00,3.00) 和 (3.00,3.00) ,只需发射一只飞行轨迹为 y=-x2+4x 的小鸟即可消灭它们。

第二个关卡中有 5 只小猪,但经过观察我们可以发现它们的坐标都在抛物线 y=-x2+6x 上,故 Kiana 只需要发射一只小鸟即可消灭所有小猪。

想到了DP但后来不知道怎么转换。。后来发现要状态压缩。
回去补补状态压缩dp。二进制我还不怎么会。

STD.CPP

//std ans of t3#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<string>#include<algorithm>#include<queue>#include<vector>using namespace std;#define N 18const double eps=1e-9;int T,n,m;double a,b,x[N+1],y[N+1];int birds[N+1][N+1],f[1<<N];void clear(){    n=m=0;    a=b=0.0;    memset(x,0,sizeof(x));memset(y,0,sizeof(y));    memset(birds,0,sizeof(birds));memset(f,0,sizeof(f));}int dcmp(double x){    if (x<=eps&&x>-eps) return 0;    if (x>eps) return 1;    return -1;}void calc(double &a,double &b,int id,int jd){    a=b=0;    double A=x[id],B=y[id],C=x[jd],D=y[jd];    if (dcmp(A-C)==0) return;    a=(B*C-A*D)/(A*A*C-A*C*C);    b=(B*C*C-D*A*A)/(A*C*C-A*A*C);}bool on(int id,double a,double b){    double A=x[id],B=y[id];    if (dcmp(A*A*a+A*b-B)==0) return true;    else return false;}void init(){    for (int i=1;i<=n;++i)        for (int j=i+1;j<=n;++j)        {            calc(a,b,i,j);            if (a>=0) continue;            for (int k=1;k<=n;++k)                if (on(k,a,b)) birds[i][j]|=1<<(k-1);        }}int main(){    //freopen("angrybirds.in","r",stdin);    //freopen("angrybirds.out","w",stdout);    scanf("%d",&T);    while (T--)    {        clear();        scanf("%d%d",&n,&m);        for (int i=1;i<=n;++i) scanf("%lf%lf",&x[i],&y[i]);        init();        memset(f,127,sizeof(f));        f[0]=0;        for (int i=0;i<1<<n;++i)        {            for (int j=1;j<=n;++j)                if ((i&(1<<(j-1)))==0)                {                    for (int k=j+1;k<=n;++k)                        if ((i&(1<<(k-1)))==0)                            f[i|birds[j][k]]=min(f[i|birds[j][k]],f[i]+1);                    f[i|(1<<(j-1))]=min(f[i|(1<<(j-1))],f[i]+1);                    break;                }        }        printf("%d\n",f[(1<<n)-1]);    }}

动归大法好,关键时刻把命保。

原创粉丝点击