给你一个长 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),并且其往左上(必须为X)、左下(必须为X)、右上(必须为O)、右下(必须为O)四个方向扩展相同的长度,且左上顶点与左下顶点之间全由X填充,右上顶点与右下顶点之间全由O填充。
我们不在意在蝴蝶形状内部是X还是O。
例如:
XAAAO
XXAOO
XAXAO
XXAOO
XAAAO
是一个蝴蝶形状(其中A表示X或O)。
X
也是。
而
XAAO
XXOO
XXOO
XAAO
不是(不存在中心点)。
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"); }