10.4离线赛

来源:互联网 发布:淘宝买书靠谱吗 编辑:程序博客网 时间:2024/06/11 18:19

NOIP2014提高组day1模拟
预分270 实分170

生活大爆炸版石头剪刀布
应得100 实得100
题意:多了两种出法,输赢如下表
这里写图片描述
每个人的出法都有周期性,问n回合后的得分。

数据:n∈[1,200]

数据太小,一遍循环就可以过了,分数只需要打个表就行,代码很短

联合权值
应得100 实得0

题意:在一棵树上每个点有点权,边的长为一,求所有两点间距离为二的点对的点权乘积的和,和最大的点权乘积。和要对10007取模。

数据:对于60%,n∈[1,2000]
对于100%,n∈[1,200000]
边权∈[1,10000]

这个实得分数其实是想错了的错误得分。
因为两点之间差距为二,那么想当然的变成了第i层与第i-2层的和的乘积,
但是在不同的子树上这样是错的。
然后我在暴力里加了两个东西
1、儿子节点与爷爷节点(父亲的父亲)的乘积
2、与同个子树上一层的乘积(前缀和)
这样就对了
最大的和与上同类

#include<bits/stdc++.h>#define M 200005#define Mod 10007#define ll long longusing namespace std;vector<int>edge[M];ll ans,mx,A[M];void f(int x,int fa1){    ll cnt=0;//前缀和    ll mx1=0,mx2=0;    for(int i=0;i<edge[x].size();i++){        int y=edge[x][i];        if(y==fa1)continue;        f(y,x);        ans+=A[y]*A[fa1];ans%=Mod;//和爷爷        ans+=A[y]*cnt;ans%=Mod;//这一层        cnt+=A[y];//前缀和的算法,这个可以手推一下        mx=max(mx,A[y]*A[fa1]);        if(A[y]>mx1)mx2=mx1,mx1=A[y];        else if(A[y]>mx2)mx2=A[y];        mx=max(mx,mx1*mx2);//mx1和mx2是这层的最值    }}int main(){    int n;    scanf("%d",&n);    for(int i=1;i<n;i++){        int x,y;        scanf("%d%d",&x,&y);        edge[x].push_back(y);        edge[y].push_back(x);    }    for(int i=1;i<=n;i++)scanf("%lld",&A[i]);    f(1,0);    printf("%lld %lld\n",mx,ans*2%Mod);    return 0;}

飞扬的小鸟
应得70 实得70

题意:模拟一个游戏
1、游戏界面是一个长为 n,高为 m 的二维平面,其中有k 个管道(忽略管道的宽度)。
2、小鸟始终在游戏界面内移动。小鸟从游戏界面最左边 任意整数高度位置出发,到达游戏界面最右边时,游 戏完成。
3、小鸟每个单位时间沿横坐标方向右移的距离为 1,竖直移动的距离由玩家控制。如 果点击屏幕,小鸟就会上升一定高度 X,每个单位时间可以点击多次,效果叠加; 如果不点击屏幕,小鸟就会下降一定高度 Y。小鸟位于横坐标方向不同位置时,上 升的高度 X 和下降的高度 Y 可能互不相同。
4、小鸟高度等于 0 或者小鸟碰到管道时,游戏失败。小鸟高度为 m 时,无法再上升。
若能,则输出1和最小步数,否则输出0和能经过的柱子

数据:对于70%,n∈[5,1000],m∈[5,100]
对于100%,n∈[5,10000],m∈[5,1000]

先是一个dp[ i ][ j ] 在坐标[i,j]上跳了几次
这样每次只往上一层的状态上移下移就行
70是没有优化,每个点一直更新
100就是改成完全背包,因为画一下图就能知道有几个点的计算是重复的,那么可以直接加,这样就该成了O(1)。
但是一开始还是错,错在了两个地方
1、完全背包要把这道题中到不了的地方也要算,不然没有办法算上面的
2、那些没有用的地方最后还有清掉,不然对后面有影响

#include<bits/stdc++.h>#define M 10005using namespace std;struct node1{int up,down;}A[M];struct node2{int l,h,p;node2(){p=0;}}B[M];int dp[2][1005];int main(){    int n,m,k;    scanf("%d%d%d",&n,&m,&k);    for(int i=1;i<=n;i++)scanf("%d%d",&A[i].up,&A[i].down);//读入每个格子的上移下移量    for(int i=1;i<=k;i++){        int x;scanf("%d",&x);        scanf("%d%d",&B[x].l,&B[x].h);B[x].p=1;//用计数的方法放柱子    }    for(int i=1;i<=n;i++){        memset(dp[i%2],63,sizeof(dp[i%2]));//先清为无限大        int L,R;        if(B[i].p)L=B[i].l+1,R=B[i].h-1;//上下界        else L=1,R=m;        int p=1;        for(int j=1;j<=m;j++){            int d=j+A[i].up;            if(d>m)d=m;            if(dp[i%2][d]>dp[1-i%2][j]+1)dp[i%2][d]=dp[1-i%2][j]+1;//完全背包开始是只走一步        }        for(int j=1;j<=m;j++){            int d=j+A[i].up;            if(d>m)d=m;            if(dp[i%2][d]>dp[i%2][j]+1)dp[i%2][d]=dp[i%2][j]+1;//最后一步一步累加的走        }        for(int j=1;j<=m;j++)            if(j-A[i].down>=L&&j-A[i].down<=R&&dp[i%2][j-A[i].down]>dp[1-i%2][j])dp[i%2][j-A[i].down]=dp[1-i%2][j];        for(int j=1;j<=m;j++){            if(dp[i%2][j]<=10000000&&j<=R&&j>=L)p=0;//判断不行的时候也要跳过那些不符合的地方            else dp[i%2][j]=10000005;        }        if(p){            int cnt=0;            for(int j=0;j<i;j++)if(B[j].p)cnt++;            printf("0\n%d\n",cnt);            return 0;         }    }    int ans=1e9;    for(int i=1;i<=m;i++)if(ans>dp[n%2][i])ans=dp[n%2][i];    printf("1\n%d\n",ans);    return 0;}

另:这次考试太浪了,第二题暴力都没交,交了的话至少想法错了还能弄个60分

原创粉丝点击