Wannafly挑战赛3

给你一个长 n 的序列,m 次查询

每次查询给一个 x,然后:

从序列的最左端 1 开始,每次随机的选择一个右端点 r,如果两个端点间的区间和不超过 x ,就进行一次分割,然后把左端点变成 r + 1, 否则一直随机下去。

问这样分割出来的期望段数

输入描述:

第一行两个数 n,m
之后一行 n 个数表示这个序列
之后m行每行一个数 x,表示求每段的和不大于 x 的情况下切割的期望段数

输出描述:

m 行,每行一个保留到小数点后2位的数表示答案
如果无论如何都没有合法的切割方案,输出"YNOI is good OI!",不含引号

示例1

输入

5 6
1 2 3 4 5
4
5
6
7
8
9

输出

YNOI is good OI!
4.25
3.83
3.58
3.58
3.11

说明

对于30%的数据,n , m <= 10
对于60%的数据,n <= 1000 , m <= 10
对于80%的数据,n <= 100000 , m <= 100
对于100%的数据,n <= 100000 , m <= 500 , 0 <= a[i] <= 1000 , x <= 1000000

看了好久才知道题意。。。
就是把n个数分段,要求每一段的区间和小于等于x,然后求一下期望段数
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=1e5+88;
int a[N],sum[N],n,m,x;
double dp[N],Sum[N];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) {scanf("%d",a+i);sum[i]=a[i]+sum[i-1];}
    while(m--){
    bool ok=1;
    scanf("%d",&x);
    int pos=n;
    for(int i=n;i>=1;--i) {
        if(a[i]>x) {ok=0;break;}
        else {
            while(sum[i-1]+x<sum[pos]) --pos;
            double shu=pos-i+1;
            dp[i]=(Sum[i+1]-Sum[pos+2])/shu+1;
        }
        Sum[i]=Sum[i+1]+dp[i];
    }
    if(!ok) puts("YNOI is good OI!");
    else printf("%.2f
",dp[1]);
    }
}

题目描述

给一个数组{a},定义 h(a,b)为在十进制下 a + b 与 a 的位数差,求 ,0的位数为1。
 

输入描述:

第一行读入一个正整数 n (1 <= n <= 105)。

第二行读入 n 个非负整数,第 i 个表示a[i] (0 <= a[i] <= 108)。

输出描述:

一行表示答案。
示例1

输入

10
0 1 2 3 4 5 6 7 8 9

输出

20

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+88;
int sum[N],n,a[N],san[N],b[N];
long long s[15];
void add(int p){
    for(;p<=n+55;p+=(p&(-p))) ++sum[p];
}
int query(int p){
    int ans=0;
    for(;p;p-=(p&(-p))) ans+=sum[p];
    return ans; 
}
int main(){
    long long ans=0;
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%d",a+i),b[i]=a[i];
    sort(b+1,b+n+1);
    b[0]=0;
    s[1]=0,s[2]=10;
    for(int i=3;i<=14;++i) s[i]=s[i-1]*10;
    for(int i=1;i<=n;++i) san[i]=lower_bound(b+1,b+n+1,a[i])-b;
    for(int i=n;i>=1;--i){
        int now=a[i],wei=0,cha;
        if(!now) wei=1;
        while(now){
            now/=10;
            ++wei;
        }
        int ct=wei;
        while(1){
            ++wei;
            cha=s[wei]-a[i];
            int xia=lower_bound(b+1,b+n+1,cha)-b-1;
            if(xia==n) break;
            ans+=query(n+1)-query(xia);
        }
        add(san[i]);
    }
    printf("%lld
",ans);
}
给定一个 n*m 的矩阵,矩阵元素由X和O构成,请求出其中最大的蝴蝶形状。
蝴蝶形状的定义如下:
存在一个中心点(必须为X),并且其往左上(必须为X)、左下(必须为X)、右上(必须为O)、右下(必须为O)四个方向扩展相同的长度,且左上顶点与左下顶点之间全由X填充,右上顶点与右下顶点之间全由O填充。
我们不在意在蝴蝶形状内部是X还是O。
例如:
    XAAAO
    XXAOO
    XAXAO
    XXAOO
    XAAAO
是一个蝴蝶形状(其中A表示X或O)。
    X
也是。

    XAAO
    XXOO
    XXOO
    XAAO
不是(不存在中心点)。

输入描述:

第一行两个整数n, m表示矩阵的大小 (1 <= n, m <= 500);
接下来 n 行,每行一个长度为 m 的字符串表示矩阵,矩阵元素保证由X和O构成。

输出描述:

一行一个整数表示最大的蝴蝶形状的对角线的长度。

示例1

输入

5 5
XOOOO
XXOOO
XOXOO
XXOOO
XOOOO

输出

5

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char mp[508][508];
int n,m;
bool Ju(int x,int y,int k,int size){
    if(mp[x+k][y+k]=='O'||mp[x+k][y+size-1-k]=='X') return true;
    if(mp[x+size-1-k][y+k]=='O'||mp[x+size-1-k][y+size-1-k]=='X') return true;
    return false;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;++i) scanf("%s",mp[i]);
    int maxx=min(n,m);
    if((maxx&1)^1) --maxx;
    bool ok=0;
    for(int size=maxx;~size;size-=2) if(ok) break; else  for(int i=0;i<=n-size;++i){
        int sj=(size+1)/2;
        for(int j=0;j<=m-size;++j) {
            if(mp[i+sj-1][j+sj-1]!='X') continue;
            bool fl=1;
            for(int k=0;k<sj-1;++k) if(Ju(i,j,k,size)) {fl=0;break;}
            if(!fl) continue;
            for(int k=0;k<size;++k) if(mp[i+k][j]!='X') {fl=0;break; }
            if(!fl) continue;
            for(int k=0;k<size;++k) if(mp[i+k][j+size-1]!='O'&&size!=1) {fl=0;break;}
            if(fl) {ok=1;break;}
        }
        if(ok) {printf("%d
",size);break;}
    }
    if(!ok) puts("0");
}
原文地址:https://www.cnblogs.com/mfys/p/7818846.html