[计蒜客NOIP模拟赛]2017.7.28Day1回顾反思总结

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[计蒜客NOIP模拟赛]2017.7.28Day1回顾反思总结相关的知识,希望对你有一定的参考价值。

D1T1 打地鼠

题目链接

反思-

比赛得分-0

思考:

比赛时,以为T1是一道常规模拟题目,没怎么看数据范围。直接手动模拟,模拟完之后太自信也没有造数据Hack自己的程序。直接导致爆0。同时发现自己对二维前缀和的学习也只是在皮毛之上,没有深入思考与理解。

 

解题思路-

将图像旋转45°之后用二维前缀和维护,每次O(1)查询,时间复杂度O(N*N)。

但是目前觉得这个图像旋转45°难以理解,打算手动模拟加深理解。

 

标程

#include<bits/stdc++.h>
using namespace std;
int n,m,k;
int a[4050][4050],b[4050][4050],s[4050][4050],vis[4050][4050];
int main(){
    //freopen("mouse10.in","r",stdin);
    //freopen("mouse10.ans","w",stdout);
    scanf("%d%d%d",&n,&k);m=n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&a[i][j]);
    int l=n+n-1,ll=2*l-1;
    for(int i=1;i<=ll;i++){
        if(i>=n&&(i-n)%2==0){
            int num=(i-n)/2+1;
            //if(i==9) cout<<num<<endl;
            for(int j=num;j<=num+n-1;j++)
                b[j][i+1-j]=a[j-num+1][num],vis[j][i+1-j]=1;
        }
    }
    for(int i=1;i<=l;i++)
        for(int j=1;j<=l;j++)
            s[i][j]=b[i][j]+s[i-1][j]+s[i][j-1]-s[i-1][j-1];
    int ans=0;
    for(int i=1;i<=l;i++)
        for(int j=1;j<=l;j++)
            if(vis[i][j]){
                int zsx=max(1,i-k+1),zsy=max(1,j-k+1),zxx=min(l,i+k-1),zxy=max(1,j-k+1);
                int ysx=max(1,i-k+1),ysy=min(l,j+k-1),yxx=min(l,i+k-1),yxy=min(l,j+k-1);
                ans=max(ans,s[yxx][yxy]-s[ysx-1][yxy]-s[zxx][zxy-1]+s[zsx-1][zsy-1]);
        }
    printf("%d\n",ans);
}

 

D1T2 蒜头君的树

反思-

比赛得分-30

思考:

比赛时,以为是用数据结构维护,生硬套上了树剖模板,但是得分只有30。没有深入去思考,每个变化的边的所带来的影响。

 

解题思路-

乘法原理在树上的运用,我们假设结点u是结点v的父亲,其边权为w。那么这条边权会被最终答案计算多少次呢?没错就是除儿子v及其子结点的数量*儿子v及其子结点的数量。

修改的话只考虑,修改的那条边对其他结点的影响。 我们假设修改的结点是 x,那么影响的结点数量就是x及其子孙数量*其他结点数。

#include <cstdio>
#include <algorithm>
#include <vector>
typedef long long ll;
const int maxn = 1e5+5;

struct node{
    int v,w;
};

std::vector<node>G[maxn];
int n,m,bian[maxn];
ll sum[maxn],dp[maxn];

int Read(){
    int ch = 0;
    char c;
    c = getchar();
    while( c<0 || c>9) c = getchar();
    while( c>=0 && c<=9) {
    ch = ch*10+c-0;
    c = getchar();
    }
    return ch;
}

void dfs(int x,int fa){
    sum[x] = 1;
    int Size = G[x].size();
    for(int i=0;i<Size;i++){
        int v = G[x][i].v;
        int w = G[x][i].w;
        if(v==fa) continue;
        dfs(v,x);
        sum[x]+=sum[v];
        dp[x]+=(dp[v]+((n-sum[v])*sum[v])*w); //关键部分 
    }
}

void AddEdge(int u,int v,int w){
    node now;
    now.v=v;
    now.w=w;
    G[u].push_back(now);
    now.v=u;
    G[v].push_back(now);
}

int main(){
    n = Read();
    for(register int i=1;i<n;i++){
        int v,w;
        v = Read();
        w = Read();
        AddEdge(i+1,v,w);
        bian[i+1]=w;
    }
    dfs(1,0);
    printf("%lld\n",dp[1]);
    m = Read();
    for(int i=1;i<=m;i++){
        int x,y;
        x = Read();
        y = Read();
        ll ans = dp[1]+sum[x]*(n-sum[x])*(y-bian[x]);//只考虑修改的边影响的结果 
        bian[x] = y;
        dp[1] = ans;
        printf("%lld\n",ans);
    }
    return 0;
}

 

D1T3 蒜头君的坐骑

题目链接

反思-

比赛得分-0

思考:

比赛时,在T2耗费了两小时,这个时间没有时间思考了。所以草草写了一个我自己都看不懂的辣鸡暴力,成功爆0!

 

解题思路-

暴力搜索30分

用dp[n][m][k]表示牛神现在在(n,m)点,已经使用了k次技能.对于每次决策,如果不使用技能,可以转移到dp[n][m+1][k],dp[n+1][m][k],如果使用技能,则可通过dfs搜索可以转移到的每一个点,时间复杂度O(n*m*k).

不得不说这是第一次见到用DFS来求DP值,算是大开眼界了。反反复复阅读与抄写了四遍之后。看懂了,DFS和DP的含义。

#include<bits/stdc++.h>
using namespace std;
int n,m,t,k,h,atk;
int dp[1050][1050][15],mp[1050][1050];
int cal(int x,int y,int at){
     //计算怪物对你造成的伤害 h-1的原因是如果h==at那么应该是秒杀不造成伤害 
    return (h-1)/at*mp[x][y];     
}
void dfs(int x,int y,int res,int st,int at,int dam){
    if(st) dam+=cal(x,y,at); //在使用技能时,应计算是否受到伤害 
    //更新最终停止在x,y点的使用技能情况下的最小伤害值 太妙了 
    if(st==k) {dp[x][y][res+1]=min(dp[x][y][res+1],dam);return;} 
    if(x+1<=n) dfs(x+1,y,res,st+1,at+mp[x+1][y],dam);//往下走的情况 
    if(y+1<=m) dfs(x,y+1,res,st+1,at+mp[x][y+1],dam);//往右走的情况 
}
int main(){
    scanf("%d%d%d%d%d%d",&n,&m,&t,&k,&h,&atk);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&mp[i][j]); 
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            for(int l=0;l<=t;l++)
                dp[i][j][l]=999999999;
    //在起点没有使用过技能所以为0 
    dp[1][1][0]=0;
    for(int l=0;l<=t;l++)
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
                //先考虑如果不使用技能,往下走的情况的最小伤害 
                if(i+1<=n)
                dp[i+1][j][l]=min(dp[i+1][j][l],dp[i][j][l]+cal(i+1,j,atk));
                //不使用技能,往右走的最小伤害 
                if(j+1<=m)
                dp[i][j+1][l]=min(dp[i][j+1][l],dp[i][j][l]+cal(i,j+1,atk));
                //如果技能还没使用完 那么就考虑一下在此点使用技能之后的情况 
                if(l!=t)
                dfs(i,j,l,0,atk,dp[i][j][l]);
            }
    cout<<dp[n][m][t]<<endl;
}

 

最终总结反思

技不如人就是事实,没有天赋还天天颓。再这样下去,NOIP一等都是一个问题,所以拼命努力吧~

还有就是考试技巧非常重要,多参加比赛练习赛感,减少比赛失误!!!

以上是关于[计蒜客NOIP模拟赛]2017.7.28Day1回顾反思总结的主要内容,如果未能解决你的问题,请参考以下文章

计蒜客NOIP2017提高组模拟赛day1

计蒜客NOIP2017提高组模拟赛day1-展览

计蒜客 2017 NOIP 提高组模拟赛Day1 T2 小X的密室

计蒜客 2017 NOIP 提高组模拟赛Day1 T1 小X的质数 线性筛素数

火山喷发 计蒜客16862 NOIP模拟赛 概率DP

计蒜客NOIP2017提高组模拟赛day2-小区划分