Codeforces Round #345 (Div. 2) D,E

2 篇文章 0 订阅
2 篇文章 0 订阅

D

题意:题目的输入是n,a,b,T,然后输入一个长度为n的字符串。n代表字符串的长度,字符串的每一位代表一张图片,标号从1依次到n,初始时在第一张照片的位置。照片可以左右滑动,第一张照片左侧为第n张,第n张右侧为第一张(即一个圈),滑动所需要的时间为a。查看一张正常的照片所需要的时间为1,一张不正常(方向不对)的照片需要先花费时间b来改正方向,没看过的照片不能跳过,看过的照片可以跳过(即只花费滑动的时间a)。问在T时间内,最多查看几张照片。
思路:初始时的位置为0,所以一共有两种方式,往左走再回来或者往右走再回来,两种方式类似,考虑先往右走回来。往右走得越多,能回去的距离越短,所以枚举往右走的长度,求出能往左走的最大长度,所以记录往左走的最大长度,这个最大长度是递减的,复杂度O(N)就可以求出结果。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3f
const int maxn = 501000;
char s[maxn];
int tt[maxn];
int l[maxn],r[maxn];
int n,a,b,T;
int get_ans(){
    int ans = 1;
    int mm = 1;
    for(int i = 0;i < n;i ++){
        int tmp = T - l[i] - i * a;
        if(tmp < 0)break;
        ans = max(ans,i+1);

        tmp -= i * a;
        if(tmp <= 0)continue;

        for(mm = max(i+1,mm);mm < n;mm ++){
            if(tmp >= a * (n - mm) + r[mm])break;
        }
        ans = max(ans,i+1+n-mm);
    }
    return ans;
}
int main(){
    cin>>n>>a>>b>>T;
    scanf("%s",s);
    for(int i = 0;i < n;i ++){
        if(s[i] == 'w')tt[i] = b+1;
        else tt[i] = 1;
    }

    l[0] = tt[0];
    for(int i = 1;i < n;i ++){
        l[i] = l[i-1] + tt[i];
    }
    r[n-1] = tt[n-1];
    for(int i = n-2;i >= 0;i --){
        r[i] = r[i+1] + tt[i];
    }

    if(T < tt[0]){cout<<0<<endl;return 0;}
    int ans = 1;
    ans = max(ans,get_ans());

    for(int i = 1;i < n;i ++){
        int tmp = l[i];
        l[i] = r[n-i] + tt[0];
        r[n-i] = tmp - tt[0];
    }
    ans = max(ans,get_ans());
    cout<<ans<<endl;
    return 0;
}

E

题意:给出一个n*m的矩阵,矩阵中是大于0的整数。现在求一个新矩阵,新矩阵要求对于原矩阵中的某一行或者某一列中数字的大小关系不变,让新矩阵的最大值最小。
思路:首先肯定得排序,对于最小的那些数,直接赋为1,对于之后的数字,假设是(i,j),这个数字得比现在第i行和第j列上的所有的数字大,所以我维护了两个数组,rmax和cmax,记录行和列的最大值。还得与和他处于同一行或者同一列&&原矩阵中值相等的位置的最终结果相同,而这些值相等的位置又得比他所在的行和列的数字大。所以综合来看,对于原矩阵中值相等且通过行或者列可以连接起来的点可以看作一个集合,这个集合用一个YY的东西来维护,其实就是用两个数组rfa和cfa记录这一行和这一列有没有值为x的点,如果有的话就用并查集把这两个点加入同一个集合,并查集维护的时候需要维护最大值mmax。
//写完之后一股浓浓的搞麻烦了的既视感。。
代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int maxn = 1001000;
int rmax[maxn],cmax[maxn];//行最大值,列最大值
int rfa[maxn],cfa[maxn];
int ffa[maxn],mmax[maxn];
struct Node{
    int x,y,num,ans;
}node[maxn];
bool cmp1(Node a,Node b){
    return a.num < b.num;
}
bool cmp2(Node a,Node b){
    return a.x < b.x || (a.x == b.x && a.y < b.y);
}
int n,m;
bool ok(int k,int l,int r){
    return k < l || k > r;
}
int find(int x){
    return ffa[x] == x?ffa[x]:ffa[x] = find(ffa[x]);
}
void tofa(int a,int b){
    int fa = find(a);
    int fb = find(b);
    ffa[fb] = fa;
    mmax[fa] = max(mmax[fa],mmax[fb]);
}
void solve(int l,int r){
    for(int i = l;i <= r;i ++){
        ffa[i] = i;
        mmax[i] = max(rmax[node[i].x],cmax[node[i].y]);
    }
    for(int i = l;i <= r;i ++){
        bool flagr = ok(rfa[node[i].x],l,r),flagc = ok(cfa[node[i].y],l,r);
        if(flagr && flagc){
            rfa[node[i].x] = cfa[node[i].y] = i;
        }
        else {
            if(flagr)rfa[node[i].x] = i;
            else tofa(rfa[node[i].x],i);

            if(flagc)cfa[node[i].y] = i;
            else tofa(cfa[node[i].y],i);
        }
    }
    for(int i = l;i <= r;i ++){
        int fa = find(i);
        node[i].ans = rmax[node[i].x] = cmax[node[i].y] = mmax[fa] + 1;
    }
}
int main(){
    cin>>n>>m;
    int tttt;
    for(int i = 0;i < n;i ++){
        for(int j = 0;j < m;j ++){
            scanf("%d",&tttt);
            node[i*m+j] = (Node){i,j,tttt,1};
        }
    }
    sort(node,node+n*m,cmp1);

    for(int i = 0;i < n*m;i ++){
        for(int j = i;j <= n*m;j ++){
            if(j == n*m || node[j].num != node[i].num){
                solve(i,j-1);
                i = j-1;
                break;
            }
        }
    }
    sort(node,node+n*m,cmp2);
    for(int i = 0;i < n;i ++){
        for(int j = 0;j < m;j ++){
            printf("%d",node[i*m+j].ans);
            if(j == m-1)printf("\n");
            else printf(" ");
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值