10.4离线赛

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 long
using 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 10005
using 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分

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值