Codeforces Round #345 (Div. 2)

链接:http://www.codeforces.com/contest/651

problemA:给定两个操作手柄的初始电量a,b,只有一个充电器,每一分钟如果不充电要消耗2%,在这分钟开始时就要消耗1%结束时再消耗1%,如果连上充电器会增加1%的电量。求两个手柄最多能撑多少分钟使得两个都有电。O(n)

分析:while下去就行了。。特判一下(1,1)的情况。

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=2000010;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
const ll INF=10000000010;
typedef unsigned long long ull;
int main()
{
    int a,b,ans=0;
    scanf("%d%d", &a, &b);
    while (a>0&&b>0) {
        if (a==1&&b==1) break ;
        ans++;
        if (a>b) swap(a,b);
        a++;b-=2;
    }
    printf("%d\n", ans);
    return 0;
}

problemB:给定一个数组a[i]。打乱重组,求最多能有多少个a[i+1]>a[i]。

分析:最多一定是每次挑出一个最长的严格上升子序列。O(n^2)

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=2000010;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
const ll INF=10000000010;
typedef unsigned long long ull;
int a[1010],q[1010];
int main()
{
    int i,j,n,mx,ans=0;
    scanf("%d", &n);
    for (i=1;i<=n;i++) scanf("%d", &a[i]);
    sort(a+1,a+n+1);
    memset(q,0,sizeof(q));
    for (i=1;i<=n;i++) {
        if (q[i]) continue ;
        mx=a[i];
        for (j=i+1;j<=n;j++)
        if (!q[j]&&a[j]>mx) {
            mx=a[j];q[j]=1;ans++;
        }
    }
    printf("%d\n", ans);
    return 0;
}

problemC:给定二维平面上n个点,求有多少对点对,两点在同一行或同一列。重点不算。

分析:sort两次,一次x优先一次y优先,算一下在同一行和同一列的点的个数即可,再减去重点的情况。O(nlogn)

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=200010;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const int INF=1000000010;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
typedef unsigned long long ull;
struct node {
    int x,y;
}a[N];
int cmd1(node a,node b) {
    if (a.x!=b.x) return a.x<b.x;
    return a.y<b.y;
}
int cmd2(node a,node b) {
    if (a.y!=b.y) return a.y<b.y;
    return a.x<b.x;
}
ll cala(ll x) {
    return x*(x-1)/2;
}
int main()
{
    int i,n,g,fx,fy;
    ll ans=0;
    scanf("%d", &n);
    for (i=1;i<=n;i++) scanf("%d%d", &a[i].x, &a[i].y);
    n++;a[n].x=a[n].y=INF;
    sort(a+1,a+n+1,cmd1);
    g=0;fx=INF;
    for (i=1;i<=n;i++)
    if (a[i].x!=fx) {
        ans+=cala(i-g);g=i;fx=a[i].x;
    }
    sort(a+1,a+n+1,cmd2);
    g=0;fy=INF;
    for (i=1;i<=n;i++)
    if (a[i].y!=fy) {
        ans+=cala(i-g);g=i;fy=a[i].y;
    }
    g=0;fx=INF;fy=INF;
    for (i=1;i<=n;i++)
    if (a[i].x==fx&&a[i].y==fy) continue ;
    else {
        ans-=cala(i-g);g=i;fx=a[i].x;fy=a[i].y;
    }
    printf("%I64d\n", ans);
    return 0;
}


problemD:手机里有n张照片(环状),首先看到的是第一张,看一张照片要花1秒,左/右滑动一次要a秒, 水平的翻转成垂直的才能看翻转一次要b秒,不允许跳过照片不看,看过的照片可以不用再看,总共有t秒时间,求最多能看多少张照片。

分析:如果从第一张开始要两边都看的话那么肯定是先向一边走走到想看的照片再向反向走,而不会一会左一会右,我们枚举这个端点,另一边二分,左右都算一次就可以了。O(nlogn)

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=500010;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
const ll INF=10000000010;
typedef unsigned long long ull;
char s[N];
int n,t,sum[N];
int get(ll a) {
    int l=0,r=n+1,mid=(l+r)/2;
    while (l+1<r)
    if (sum[mid]+a<=t) { l=mid;mid=(l+r)/2; }
    else { r=mid;mid=(l+r)/2; }
    return l;
}
int main()
{
    int i,a,b,ans=0,tot;
    scanf("%d%d%d%d", &n, &a, &b, &t);
    scanf("%s", s);
    if (s[0]=='w') sum[1]=b+1;
    else sum[1]=1;
    for (i=1;i<n;i++)
    if (s[i]=='w') sum[i+1]=sum[i]+a+b+1;
    else sum[i+1]=sum[i]+a+1;
    ans=max(ans,get(0));tot=0;
    for (i=n-1;i>=0;i--) {
        if (s[i]=='w') tot+=a+a+b+1;
        else tot+=a+a+1;
        if (tot>t) break ;
        if (get(tot)) ans=max(ans,n-i+get(tot));
    }
    for (i=n-1;i>0;i--)
    if (s[i]=='w') sum[n-i+1]=sum[n-i]+a+b+1;
    else sum[n-i+1]=sum[n-i]+a+1;
    ans=max(ans,get(0));tot=0;
    for (i=1;i<n;i++) {
        if (s[i]=='w') tot+=a+a+b+1;
        else tot+=a+a+1;
        if (tot>t) break ;
        if (get(tot)) ans=max(ans,i+get(tot));
    }
    printf("%d\n", min(ans,n));
    return 0;
}

problemE:给定一个n*m的正数表格,要求压缩这个表格使得每一行和每一列的元素相对大小不变,同时要求表格内最大元素最小。

分析:我们将这n*m个数排序,然后从小到大编号,那么我们只要考虑所在的行和列中已经存在的最大元素即可。但是这样还不够,可能会有相同大小的元素有些不会受到所在行列已填的数的影响而是受到当前的这个相同大小的元素的影响。我们对大小相同的元素做一次并查集求下联通块即可。O(k*n*m)

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=1000010;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const int INF=1000000010;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
typedef unsigned long long ull;
struct node {
    int x,y,z,ans;
}a[N];
int f[2*N],mx[2*N],mxx[2*N];
int cmd1(node a,node b) {
    if (a.z!=b.z) return a.z<b.z;
    if (a.x!=b.x) return a.x<b.x;
    return a.y<b.y;
}
int cmd2(node a,node b) {
    if (a.x!=b.x) return a.x<b.x;
    return a.y<b.y;
}
int find_fa(int x) {
    return f[x]==x ? x:f[x]=find_fa(f[x]);
}
void unit(int x,int y) {
    int fx=find_fa(x),fy=find_fa(y);
    if (fx==fy) return ;
    f[fx]=fy;mx[fy]=max(mx[fy],mx[fx]);
    mxx[fy]=max(mxx[fy],mxx[fx]);
}
int getmax(int x,int y) {
    int fx=find_fa(x);
    if (mxx[fx]==y) return mx[fx];
    return mx[fx]+1;
}
int main()
{
    int i,j,k,n,m;
    scanf("%d%d", &n, &m);
    for (i=1;i<=n;i++)
        for (j=1;j<=m;j++) {
            scanf("%d", &a[(i-1)*m+j].z);
            a[(i-1)*m+j].x=i;a[(i-1)*m+j].y=j;
        }
    sort(a+1,a+n*m+1,cmd1);
    j=1;a[n*m+1].z=INF;
    memset(mx,0,sizeof(mx));
    memset(mxx,0,sizeof(mxx));
    for (i=2;i<=n*m+1;i++)
    if (a[i].z==a[i-1].z) continue ;
    else {
        for (k=j;k<i;k++) {
            f[a[k].x]=a[k].x;f[a[k].y+n]=a[k].y+n;
        }
        for (k=j;k<i;k++) unit(a[k].x,a[k].y+n);
        for (k=j;k<i;k++) {
            a[k].ans=getmax(a[k].x,a[k].z);
            mx[a[k].x]=max(mx[a[k].x],a[k].ans);
            mx[a[k].y+n]=max(mx[a[k].y+n],a[k].ans);
            mxx[a[k].x]=mxx[a[k].y+n]=a[k].z;
        }
        j=i;
    }
    sort(a+1,a+n*m+1,cmd2);
    for (i=1;i<=n;i++) {
        for (j=1;j<=m;j++) printf("%d ", a[(i-1)*m+j].ans);
        printf("\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值