7.4集训模拟赛7(白丢了100分的一天,WTF)

 A. 侦查(tarjan缩点)

题目描述

输入格式

 

输出格式

样例

样例输入

12 11
10 11 2 3 4 5 1 1 1 1 1 1
1 2
2 3
1 3
4 5
5 6
6 7
8 9
9 12
11 12
10 11
8 10 

样例输出

8 9 10 11 12
1 2 3

 分析

我恨死这道题了,(so  easy,but......),一个break写道括号外面了,结果第二问没有输出,~~~~~~~,

这就是个简单tarjan缩点,然后记录SCC中的基地数和敌人数然后取max,在遍历一边每个点找出输出就ok,break,不要写错位置啊啊啊啊啊啊啊啊!!!

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1100;
int n,m;
int a[N];
int sum[N],summ[N],dfn[N],low[N];
int Time,tot,cnt,top;
int x,y,g[N],head[N];
bool vis[N];
int sta[N];

struct edge{
    int to;
    int ne;
}e[N<<2];

void add(int u,int v){
    e[++cnt].to = v;
    //e[cnt].w = w;
    e[cnt].ne = head[u];
    head[u] = cnt;
}

void tarjan(int u){
    dfn[u]=low[u]=++Time;
    vis[u]=1;sta[++top]=u;
    for(int i=head[u];i;i=e[i].ne){
        int v = e[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[u] = min(low[u] , low[v]);
        }
        if(vis[v]){
            low[u] = min(low[u] , dfn[v]);
        }
    }
    if(dfn[u]==low[u]){
        tot++;
        //sum[tot]+=a[u];
        while(sta[top+1]!=u){
            int v = sta[top--];
            vis[v] = 0;
            sum[tot]+=a[v];
            summ[tot]++;
            g[v] = tot;
        }
    }
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i])tarjan(i);
    }
    int jidi=-10,diren=-10;
    for(int i=1;i<=tot;i++){
        jidi = max(jidi,summ[i]);
        diren = max(diren,sum[i]);
    }
    //printf("%d  %d\n",jidi,diren);
    for(int i=1;i<=n;i++){
        if(summ[g[i]]==jidi){
            for(int j=1;j<=n;j++){
                if(g[j]==g[i]){
                    printf("%d ",j);
                }
            }
            break;
        }
    }
    printf("\n");
    for(int i=1;i<=n;i++){
        if(sum[g[i]]==diren){
            for(int j=1;j<=n;j++){
                if(g[j]==g[i]){
                    printf("%d ",j);
                }
            }
            break;//此处为窝的墓地
        }
    }
    return 0;
}

B. 借书(二分答案)

题目描述

 

 输入格式

 

 输出格式

 

 样例

样例输入

6 3 
5
7
1
17
13
10

样例输出

 7

数据范围与提示

 分析

就是道二分答案,其实这就是个题目模型,最小值最大化,最大值最小化(已经暗示是二分答案了),

Code

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n,m;
int a[N];
int maxn;
int gd[N];//差分数组,记录差值
int aa;
int cnt;


bool cheak(int x){
    aa=0,cnt=0;
    for(int i=1;i<n;i++){
        aa+=gd[i];
        if(aa>=x){//如果大于就加一,并把aa置为零
            cnt++;//方便下次在找
            aa=0;
        }
    }
    if(cnt+1>=m){//如果大于m,及能够选出m本书
        return true;//就true
    } else return false;//否则
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        maxn = max(maxn,a[i]);
    }
    sort(a+1,a+1+n);//排序
    for(int i=1;i<n;i++){
        gd[i] = a[i+1]-a[i];//差分数组
    }
    int l=0,r=maxn;
    while(l<=r){//二分
        if(r-l==1){//相差为一,就判断一下,否则就会死死死死循环
            if(cheak(r)){
                l=r;
            }
            break;
        }
        int mid = (l+r)/2;
        if(cheak(mid)){
            l=mid;//如果能cheak,说明还有更大的向上更新
        } else {//不能就得向下更新
            r=mid;
        }
    }
    printf("%d",l);
}

C. 搜城探宝(树...树形dp?)

题目描述

 

 输入格式

  输出格式

样例

样例输入

8 4 
1 2 
1 3 
2 4 
2 5 
3 6 
3 7 
6 8 
2 5 1 4 6 1 1 10 

样例输出

27

数据范围与提示

 分析

额......这道题就是树形dp,不过要考虑传送门的问题,咋办昵!!!啧啧啧啧!!!!我们建一个虚点,就是n+1,因为情况不确定,所以可以枚举每一个点,让每一个点都做一次需点n+1的右子树,然后就dfs使劲搜。xiu,不过要注意一个点当完虚点后要归位。

Code

#include<bits/stdc++.h>
using namespace std;
const int N = 50;
int ls[N],rs[N],fa[N];//左右儿子,以及父亲数组
int n,key,a[N];
int x,y,ans;

int dfs(int x,int k){
    if(x==0)return 0;//叶子节点返回0
    if(k==1)return a[x];//只有一把钥匙开当前门
    int now = 0;
    for(int i=0;i<k;i++){//钥匙从一枚举,以为可能都用于开左子树,右子树
        now = max(dfs(ls[x],i)+dfs(rs[x],k-i-1)+a[x],now);
    }
    return now;
}

int main(){
    scanf("%d%d",&n,&key);
    for(int i=1;i<=n-1;i++){
        scanf("%d%d",&x,&y);
        if(!ls[x])ls[x] = y;//如果左儿子为空
        else rs[x] = y;//否则为右儿子
        fa[y]=x;//父亲
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    ls[n+1] = 1;//虚点左儿子为根节点
    for(int i=2;i<=n;i++){
        rs[n+1] = i;
        if(ls[fa[i]]==i){//若是左儿子
            ls[fa[i]]=0;
            ans = max(ans,dfs(n+1,key+2));
            ls[fa[i]] = i;//归位
        }
        else {//是右儿子
            rs[fa[i]] = 0;
            ans = max(ans,dfs(n+1,key+2));
            rs[fa[i]] = i;归位
        }
    }
    printf("%d\n",ans);
    return 0;
}

D. MM不哭(dp)

题目描述

 

 输入格式

 

 输出格式

 

 样例

样例输入

4
3
2 2
5 8
6 1
8 7

样例输出

56

 分析

看到这想到了......

这和洛谷关路灯差不多,我们定义数组f[ i ][ j ][ 1(0) ]是处理完i到j最后停在i(0)或停到j(1)的最少消耗,那么

 

 

Code

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int n,v,x;
int f[N][N][2];
int sum[N];
struct node{
    int x;
    int w;
}e[N];

bool cmp(node a,node b){//结构体排序
    return a.x<b.x;
}

int main(){
    scanf("%d%d",&n,&v);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&e[i].x,&e[i].w);
    }
    /*v = e[v].x;//这里加不加都一样
    //printf("%d",x);//因为题中的数据就是递增的
    sort(e+1,e+1+n,cmp);//虽然说没有说
    for(int i=1;i<=n;i++){//不要问我怎么知道的
        if(v==e[i].x){//问就是歪打正着
            v=i;
        }
    }*/
    for(int i=1;i<=n;i++){
        sum[i] = sum[i-1]+e[i].w;//前缀和
    }
    memset(f,0x3f,sizeof(f));//初始化最大值
    f[v][v][1]=f[v][v][0] = 0;//在v位置没动时消耗为0
    for(int l = 2;l <= n;l++){
        for(int i=1;i+l-1<=n;i++){
            int j = i+l-1;
            if(i < x-l+1)continue;//i不能在范围之外
            //if(j>n)break;
            int n1=sum[i]+sum[n]-sum[j];
            int n2=sum[i]+sum[n]-sum[j];
            int n3=sum[i-1]+sum[n]-sum[j-1];
            int n4=sum[i-1]+sum[n]-sum[j-1];
            f[i][j][0] = min(f[i+1][j][0]+n1*(e[i+1].x-e[i].x),f[i+1][j][1]+n2*(e[j].x-e[i].x));//两个(额,或者说四个)状态
            f[i][j][1] = min(f[i][j-1][0]+n3*(e[j].x-e[i].x),f[i][j-1][1]+n4*(e[j].x-e[j-1].x));
        }
    }
    printf("%d\n",min(f[1][n][0],f[1][n][1]));//取两种情况的最小值
    return 0;
}

 恭喜你找到一只正在洗澡的pig,稍等一会,分析马上来

由于这是记录日常博客,可能题分析的不是太多(主要是时间不够),那就贴上教练博客

也算偏偏访量吧

posted @ 2020-07-04 21:44  LightyaChoo  阅读(189)  评论(0编辑  收藏  举报