2016 Multi-University Training Contest 10

1 篇文章 0 订阅

开始刷多校,今天第一弹。
话说,多校的题目真的好难。。。

Median HDU 5857

给定一个有序序列,然后给定两个区间[l1,r1],[l2,r2]产生新的序列。
要求新序列的中位数。
分三种情况考虑。
1.区间没交集。
2.区间半交。
3.区间全包裹。
各自找到自己的位置就好。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int a[100005];
int T,n,m,l1,l2,r1,r2;

double find(int a[],int x){
    if(r1<=l2){
        if(x<=r1-l1+1) return a[l1+x-1];
        else return a[l2+x-1-r1+l1-1];
    }
    else if(r1<=r2){
        if(x<=l2-l1) return a[l1+x-1];
        else if(x>r1-l1+1+r1-l2+1) return a[l2+x-r1+l1-1-1];
        else return a[l2+(x-l2+l1+1)/2-1];
    }
    else{
        swap(r1,r2);  // l1,r2,r1,l2 
        if(x<=l2-l1) return a[l1+x-1];
        else if(x>r1-l1+1+r1-l2+1) return a[l2+x-r1+l1-1-1];
        else return a[l2+(x-l2+l1+1)/2-1];
    }
}

int main(){
    cin>>T;
    while(T--){
        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%d%d",&l1,&r1,&l2,&r2);
            int len = r1-l1+1 + r2-l2+1;
            if(l1>l2){
                int t =l1;l1=l2;l2=t;
                    t =r1;r1=r2;r2=t;
            }
            double mid; 
            if(len&1) mid = find(a,len/2+1);
            else mid = 0.5*find(a,len/2) + 0.5*find(a,len/2+1);
            printf("%.1lf\n",mid);
        }
    } 

    return 0;
} 

Hard problem

解析几何吧。先建系算出交点的坐标,然后就能算出来了。

#include <cstdio>
#include <cmath>
#include <iostream>

using namespace std;

double calc(int l){
    double t1 = asin(sqrt(14.0)/8.0);
    double t2 = asin(sqrt(14.0)/4.0);
    double s2 = l * l * 1.0 / 8 * t2 * 2;
    double s1 = l * l * 1.0 / 2 * t1 * 2 - sqrt(7) / 8 * l * l; 
    return (s2 - s1)*2.0;
}

int main(){
    int T,l;
    cin>>T;
    while(T--){
        cin>>l;
        printf("%.2lf\n",calc(l));  
    }
    return 0;
} 

Death Sequence

动规题。
先算i在第几轮死掉。有方程f[i]=i%k?f[i-i/k-1]+1:0;
然后累计前面死的人的个数就好了。
前几轮死的人说 a[i]=i%k?a[i-i/k-1]:i/k+1;
加上预处理的left[f[i]]即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;
const int MAXN = 3000010; 
int ans[MAXN],f[MAXN],a[MAXN],LEFT[MAXN];
int T,n,k,q,x;

void solve(){
    int t = n;
    int tot = 0;
    LEFT[0] = 0;
    while(t){
        tot++;
        LEFT[tot] = LEFT[tot-1]+(t-1)/k+1;
        t-=(t-1)/k+1;
    }
    memset(f,0,sizeof(f));
    memset(a,0,sizeof(a));
    for(int i=0;i<n;i++){
        f[i]=(i%k)?f[i-i/k-1]+1:0;
        a[i]=(i%k)?a[i-i/k-1]:i/k+1;
    }

    for(int i=0;i<n;i++){
        int t=LEFT[f[i]]+a[i];
        ans[t]=i;
    }
}

int main(){
    cin>>T;
    while(T--){
        memset(ans,0,sizeof(ans)); 
        scanf("%d%d%d",&n,&k,&q);
        solve();
        for(int i=1;i<=q;i++){
            scanf("%d",&x);
            printf("%d\n",ans[x]+1);
        } 
    }
    return 0;
} 

Counting Intersections

给定一系列平行于坐标轴的直线,求其交点的个数。
参考线段树扫描线做法。
对于横着的线段,左端点+1,右端点-1。这样累计的时候可以巧妙的去掉没有交点的线。对于竖着的线段,就查询。
处理的时候需要离散化。
以及ans要用long long

#include <cstdio>
#include <cstring>
#include <iostream>
#include <climits>
#include <algorithm>
#include <map>
#define LL long long 

using namespace std;

const int MAXN = 100005;

struct node{
    int tp,x,y,y2;
}info[MAXN*2];
int a[MAXN*2],sum[MAXN*2],Maxn;
map<int,int> mp;

bool cmp(node a,node b){
    return (a.x<b.x)||(a.x==b.x&&a.tp<b.tp);
}

void insert(int BIT,int tp,int x,int y,int y2){
    info[BIT].tp=tp;
    info[BIT].x = x;
    info[BIT].y = y;
    info[BIT].y2=y2;
}

int lowbit(int k){return k&(-k);}

void add(int k,int delta){
    while(k<=Maxn){
        sum[k]+=delta;
        k+=lowbit(k);
    }
}

int query(int k){
    int s = 0;
    while(k){
        s+=sum[k];
        k-=lowbit(k);
    }
    return s;
}

int main(){
    int T,n;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        int tot=0,all=0;
        for(int i=1;i<=n;i++){
            int x1,y1,x2,y2;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            if(x1==x2){//竖 1 
                if(y1>y2) swap(y1,y2);
                insert(++tot,1,x1,y1,y2);
                a[++all]=y1;
                a[++all]=y2; 
            } else {//横 0 
                if(x1>x2) swap(x1,x2);
                insert(++tot,0,x1,y1,1); 
                insert(++tot,0,x2+1,y2,-1);
                a[++all]=y1;
            }
        }
        sort(a+1,a+1+all);
        int cnt = 0;
        mp.clear();
        for(int i=1;i<=all;i++)
            if(!mp[a[i]]) mp[a[i]]=++cnt;
        Maxn = cnt + 1;
        memset(sum,0,sizeof(sum));
        sort(info+1,info+1+tot,cmp);
        LL ans = 0;

        for(int i=1;i<=tot;i++){
            if(info[i].tp==0){
                int tp = mp[info[i].y];
                add(tp,info[i].y2);
            } else {
                int l = mp[info[i].y],r=mp[info[i].y2];
                ans += query(r) - query(l-1);
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
} 

Water problem

求 1~n 这n个数字的英文写法的总长度. (不算空格和连字符)
模拟题。
特殊处理1-19。20-1000的话直接算个位十位+百位就行了。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int bit1[] = {4,3,3,5,4,4,3,5,5,4,3,6,6,8,8,7,7,9,8,8};
int bit2[] = {0,0,6,6,5,5,5,7,6,6};
int hundred, thousand;
int cnt[1100];
void solve(){
    hundred = 7; thousand = 8;
    cnt[1000] = 11;
    for(int i=1; i<1000; i++) {
        if(i < 20) cnt[i] = bit1[i];
        else if(i < 100){
            int m = i;
            cnt[i] = bit2[m/10];
            if(m%10) cnt[i] += bit1[m%10];
        }
        else {
            int m = i;
            cnt[i] = bit1[m/100] + hundred;
            if(!(m%100)) continue;
            cnt[i] += cnt[m%100] + 3;
        }
    }
    for(int i=1; i<=1000; i++) cnt[i] += cnt[i-1];
}
int main(){
    solve(); 
    int T; 
    cin>>T;
    while(T--){
        int n;
        scanf("%d",&n);
        printf("%d\n",cnt[n]);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值