CF 345 Div. 2

《Alive》  

A. Joysticks

有两个游戏柄和一个充电器,初始时两个游戏柄的电量分别为a%和b%,某个游戏柄如果连接充电器的话每分钟可以提升1%的电量,如果不连接充电器每分钟掉2%的电量,如果某游戏柄的电量<=0就不能玩。问最多能玩多久?
1a1,a21001 \leq a_1 , a_2 \leq 100

输入:  
1 1  
输出:  
0  
输入:  
3 5  
输出:  
6  
输入:  
4 4  
输出:  
5  

.
.
.
.
.
.
.
.
.
范围小。。枚举。。策略是贪心。。哪个电量少就给哪个充电。。

//author: CHC
//First Edit Time:	2016-03-12 11:29
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <algorithm>
#include <limits>
using namespace std;
typedef long long LL;
const int MAXN=1e+4;
const int MAXM=1e+5;
const int INF = numeric_limits<int>::max();
const LL LL_INF= numeric_limits<LL>::max();

int main()
{
    int a,b;
    while(~scanf("%d%d",&a,&b)){
        int ans=0;
        while(a>0&&b>0){
            if(a<b)swap(a,b);
            ++ans;
            b++;
            a-=2;
            if(a<0)--ans;
            //printf("%d %d\n",a,b);
        }
        printf("%d\n",ans);
    }
    return 0;
}

扩展

如果数据量大,就是不用枚举或者单位为毫秒或者微秒。。1a,b10101 \leq a , b \leq 10^{10} 怎么求?

B. Beautiful Paintings

给一个长度为n(1n10001 \leq n \leq 1000)的数组,对于每个数字1ai10001 \leq a_i \leq 1000,把这个数组的顺序重新组合后求最多有多少对ai1<aia_{i-1} \lt a_{i}

1ai10001 \leq a_i \leq 1000

输入:  
5  
20 30 10 50 40  
输出:  
4  
输入:  
4  
200 100 100 200  
输出:  
2  

.
.
.
.
.
.
.
.
.
.
范围小。。哈系,枚举。。

//author: CHC
//First Edit Time:	2016-03-12 13:05
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <algorithm>
#include <limits>
using namespace std;
typedef long long LL;
const int MAXN=1e+4;
const int MAXM=1e+5;
const int INF = numeric_limits<int>::max();
const LL LL_INF= numeric_limits<LL>::max();
int has[1010];
int n;
int main()
{
    while(~scanf("%d",&n)){
        memset(has,0,sizeof(has));
        for(int i=0,x;i<n;i++){
            scanf("%d",&x);
            ++has[x];
        }

        int ans=0;
        for(int i=0;i<1000;i++){
            int cnt=0;
            for(int j=1;j<=1000;j++){
                cnt+=(has[j]>0);
                has[j]--;
            }
            if(cnt<=1)break;
            ans+=cnt-1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

扩展

如果范围很大,不能使用枚举该如何做?

C. Watchmen

在二维平面上,有n个点($1 \leq n \leq 200 000 ),问有多少对点(i,j)(i \lt j)可以使得以下成立 |x_i - x_j| + |y_i - y_j| = \sqrt[2]{(x_i - x_j)^2 + (y_i - y_j)^2}$
xi,yi109|x_i|,|y_i| \leq 10^9

输入:  
3  
1 1  
7 5  
1 5  
输出:  
2  
输入:  
6  
0 0  
0 1  
0 2  
-1 1  
0 1  
1 1  
输出:  
11  

.
.
.
.
.
.
.
.
.
.
.
.
计算某行的组合+某列的组合-自己和自己的组合

//author: CHC
//First Edit Time:	2016-03-12 13:26
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <algorithm>
#include <limits>
using namespace std;
typedef long long LL;
const int MAXN=200000+100;
const int INF = numeric_limits<int>::max();
const LL LL_INF= numeric_limits<LL>::max();
struct point {
    int x,y;
}cs[MAXN];
int cmp(const point &x,const point &y)
{
    if(x.x!=y.x)return x.x<y.x;
    return x.y<y.y;
}
int A[MAXN*2];
int n;
int tmp[MAXN*2];
int main()
{
    while(~scanf("%d",&n)){
        for(int i=0;i<n;i++){
            scanf("%d%d",&cs[i].x,&cs[i].y);
            A[i<<1]=cs[i].x;
            A[i<<1|1]=cs[i].y;
        }
        sort(A,A+(n<<1));
        int tn=unique(A,A+(n<<1))-A;
        memset(tmp,0,sizeof(tmp));
        for(int i=0;i<n;i++){
            int pos = lower_bound(A,A+tn,cs[i].x)-A;
            ++tmp[pos];
        }
        LL ans = 0;
        for(int i=0;i<n;i++){
            int pos = lower_bound(A,A+tn,cs[i].x)-A;
            if(tmp[pos]){
                //printf("x:%d %d\n",cs[i].x,tmp[pos]);
                ans += 1LL*(tmp[pos]-1)*tmp[pos]/2;
                tmp[pos]=0;
            }
        }
        for(int i=0;i<n;i++){
            int pos = lower_bound(A,A+tn,cs[i].y)-A;
            ++tmp[pos];
        }
        for(int i=0;i<n;i++){
            int pos = lower_bound(A,A+tn,cs[i].y)-A;
            if(tmp[pos]){
                //printf("y:%d %d\n",cs[i].y,tmp[pos]);
                ans += 1LL*(tmp[pos]-1)*tmp[pos]/2;
                tmp[pos]=0;
            }
        }
        //printf("%lld\n\n",ans);
        sort(cs,cs+n,cmp);
        int cnt=1;
        int tx=cs[0].x,ty=cs[0].y;
        for(int i=1;i<n;i++){
            //printf("h:%d %d\n",cs[i].x,cs[i].y);
            if(tx==cs[i].x&&ty==cs[i].y){
                ++cnt;
                //printf("%d %d %d\n",cs[i].x,cs[i].y,cnt);
            }
            else {
                ans-=1LL*(cnt-1)*cnt/2;
                cnt=1;
                tx=cs[i].x;ty=cs[i].y;
            }
        }
        ans-=1LL*(cnt-1)*cnt/2;
        printf("%lld\n",ans);
    }
    return 0;
}
/*
 * #1 : 越界
 * */

D.

有n张图片在手机里(1n51051 \leq n \leq 5*10^5),看一张图片需要1秒,看相邻的图片需要左划或者右划,左划或者右划需要a秒,旋转一张图片需要b秒,手机是竖着的,有的图片需要横着看,不能旋转手机,只能旋转图片,如果一张图片看过,那么再次看它会被忽略,一开始打开手机看到的是第一张图片
给n,a,b,T,问最多能看多少张图片

输入:  
4 2 3 10  
wwhw  
输出:  
2  
输入:  
5 2 4 13  
hhwhh  
输出:  
4  
输入:  
5 2 4 1000  
hhwhh  
输出:  
5  
输入:  
3 1 100 10  
whw  
输出:  
0  

.
.
.
.
.
.
.
.
.
.
.
只有四种情况:

  1. 从第一张一直往右边看
  2. 从第一张一直往左边看
  3. 从第一张先往左边看,再往右边看
  4. 从第一张先往右边看,再往左边看
    只需要固定一个点,然后二分求就可以了复杂度O(nlogn)O(nlogn)。。注意这里如果不预处理,复杂度会退化成O(n2logn)O(n^2logn)
//author: CHC
//First Edit Time:	2016-03-12 19:30
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <algorithm>
#include <limits>
using namespace std;
typedef long long LL;
const int MAXN=500000 * 2 + 1000;
const int INF = numeric_limits<int>::max();
const LL LL_INF= numeric_limits<LL>::max();
int n,a,b,T;
char str[MAXN];
LL pre[MAXN];
LL Calc(int l,int r){
    LL cnt = 0;
    if(l == 0)
        cnt += (r-l)*a;
    else
        cnt += (r-l)*a + min(n-l,r-n)*a;
    /*
    for(int i=l;i<=r;i++){
        cnt += ((str[i]=='h')?0:b) + 1;
    }
    */
    return cnt + pre[r+1] - pre[l];
    //return cnt;
}
int main()
{
    while(~scanf("%d%d%d%d",&n,&a,&b,&T)){
        scanf(" %s",str);
        for(int i = 0;i < n;i++)str[i+n]=str[i];
        pre[0] = 0;
        int tn = n<<1;
        for(int i = 1;i <= tn;i++)pre[i] = pre[i-1] + (str[i-1]=='h'?0:b) + 1;
        int num = 0;
        for(int i = 0;i <= n;i++){
            int l = i , r = i + n - 1 ;
            if(l != 0) l = n;
            while(l <= r){
                int mid = (l + r) >> 1;
                LL val = Calc(i,mid);
                if(val <= (LL)T){
                    num = max(num,mid-i+1);
                    //printf(":%d %d %.*s\n",i,mid,mid-i+1,str+i);
                    l = mid + 1;
                }
                else r = mid -1;
            }
        }
        printf("%d\n",num);
    }
    return 0;
}