UOJ Logo heqingyu的博客

博客

Week 7总结

2018-04-24 06:58:01 By heqingyu

这周状态不太好,题目也比较毒瘤。。。

本来以为能400++,因为我打了四题的标算(T4模拟也算)+2题骗分

然而现实十分残酷,T3玄学(单项边,双向边。。。),T4玄学(模拟也能错我也很绝望)

T1:

本来听说是水题。。。然后就想多了想到状压去了。。。

发现每行翻转两次其实是一样的效果,于是只需翻转一次即可

大概就是说先2^n搜索出每一行是否需要翻转,然后再判断m列是否要翻转,更新答案

code:

#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[20][20];
int ans1=1e9,ans2=1e9;
char s[110];
int main(){
    scanf("%d%d",&n,&m);
      for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        for(int j=1;j<=m;j++) a[i][j]=s[j]-'0'; 
    }
      for(int s=0;s<(1<<n);s++){
        int c1=0;
        for(int i=1;i<=n;i++)
              if(s>>(i-1)&1){
                for(int j=1;j<=m;j++)
                  a[i][j]^=1;
                c1++;
              }
        int tot=0;
        for(int j=1;j<=m;j++){
            int c=0;
            for(int i=1;i<=n;i++) c+=a[i][j];
              if(n-c<c) c1++,tot+=n-c;
              else tot+=c;
        }
        if(!tot) ans1=min(ans1,c1);
        else ans2=min(ans2,tot);
        for(int i=1;i<=n;i++)
              if(s>>(i-1)&1) for(int j=1;j<=m;j++) a[i][j]^=1;
      }
    if(ans1==1e9) printf("%d",ans2);
    else printf("%d",ans1);
     return 0;
}

T2:

贪心水题,sort一遍模拟计算答案

注意long long。。。。

code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,a[1000010];
ll ans;
bool cmp(ll x,ll y){return x>y;}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    sort(a+1,a+n+1,cmp);
    for(ll i=2;i<=n;i++)ans+=(ll)((i-1)*a[i]);
    printf("%lld",ans);
    return 0;
}

T3:

被单双向边搞烦了、、干脆放弃希望。。。

发现其实是让我们求出1~n的一个全排列后计算答案

然后这里介绍一个STL:

next_permutation!!!

语法:next_permutation(c+1,c+n+1),会生成一个大于当前c的全排列,如果没有就返回false

code:

#include<bits/stdc++.h>
using namespace std;
int n,m,x,y;
int a[110][110],b[110][110];
int bel[110],ans;
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        a[x][y]++;
    }
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        b[x][y]++;
    }
    int tot=1;
    for(int i=1;i<=n;i++)bel[i]=i;
    while(next_permutation(bel+1,bel+n+1)){    
        if(tot) for(int i=1;i<=n;i++)bel[i]=i;
        int cnt=0;tot=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                cnt+=min(a[i][j],b[bel[i]][bel[j]]);
        ans=max(ans,cnt);
    }
    printf("%d",ans);
    return 0;
}

T4:

这道题我直接上模拟了。。。根本不想打什么标算。。。

code:

#include<bits/stdc++.h>
using namespace std;
int a[6000010],n,m;
int cnt;
char ch,b[5000010];
int main(){
    scanf("%d%d",&n,&m);
    getchar();
    for(int i=1;i<=n;i++){
        ch=getchar();
        a[i]=ch-'0';
    }
    scanf("%s",b+1);
    for(int i=1;i<=m;i++){
        int now=n;
        if(b[i]=='+'){
            a[now]++;
            while(a[now]==2){
                a[now]=0;
                a[--now]++;
            }
        }
        if(b[i]=='-'){
            if(a[now]) a[now]=0;
            else while(!a[now]){
                a[now]=1;
                now--;
            }
            a[now]=0;
        }
        if(b[i]=='*') n++,a[n]=0;
        if(b[i]=='/') n--;
    }
    for(int i=1;i<=n;i++)putchar(a[i]+'0');
    return 0;
}

T5:

考虑每个点只有奇偶性重要,然后考虑每个点对答案奇偶性的贡献

发现除了对角线上的点,每个点都会被计算两边,也就是对奇偶性无影响。。。

于是只需要统计对角线的奇偶性即可

code:

#include<bits/stdc++.h>
using namespace std;
int n,m;
int ans,x,y;
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j){
            scanf("%d",&x);
            if(i==j&&x) ans^=1;
        }
    while(m--){
        scanf("%d",&x);
        if(x==1||x==2) scanf("%d",&y),ans^=1;
        else printf("%d",ans);
    }
    return 0;
}

T6:

这题有两个做法,dp太玄学根本不会,。。采用了雷霸霸的做法。。。

首先找规律,竖着刷当然是从头刷到尾最优

横着刷的话就是从最左边刷到最右边。。。

于是想到一个分治的做法,就是对于一段区间[l,r],竖着刷最少次数肯定是r-l+1

那么横着刷就是这段区间的最小高度次数+除去下面一段的最小次数

这时候后者就可以分治递归下去了。。。

code:

#include<bits/stdc++.h>
using namespace std;
int ans,h[50010],n;
int solve(int l,int r,int last){
    if(l==r) return 1;
    int cnt=0,mn=1e9+1;
    for(int i=l;i<=r;i++) mn=min(mn,h[i]);
    for(int i=l;i<=r;i++){
        if(h[i]==mn) continue;
        int j;
        for(j=i;j<=r;j)if(h[++j]==mn) break; 
        cnt+=solve(i,j-1,mn);
        i=j-1;
    }
    return min(cnt+mn-last,r-l+1);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&h[i]);
    ans=solve(1,n,0);
    printf("%d",ans);
    return 0;
}

评论

暂无评论