bzoj刷水

因为最近的生活太颓废总是不做题而被老师D了一番, 所以今天晚上到bzoj上去刷了几道水题。。。。。

 

bzoj 4320: ShangHai2006 Homework

题目大意

 维护一个支持两个操作的集合:

1) 插入一个数x

2) 询问集合中所有数中 mod x 最小是多少

 

解题思路

似乎log家族没有什么好的办法解决这道题?

考虑 sqrt() 的方法。

当询问 x <= sqrt(m) 的时候, 直接存一下就可以了。

当询问 x > sqrt(m) 的时候,把n分成 n / x 块, 每一块单独考虑。

这时对于每一块, 我们需要求出的就是 >= (i * x) 的所有数中最小的那个。

填一个log会爆掉的。但是如果倒着处理, 每一次询问的就是 x 右面第一个没有被染色的点, 其实就是 疯狂的馒头 这道题, 用并查集搞一搞就可以了。

 

ExpandedBlockStart.gif
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4  #define MAXN 300003
 5  using  namespace std;
 6  int n,la[MAXN],xx[MAXN],bin[MAXN],ans[MAXN],tmp[MAXN],fat[MAXN],N= 300000,sq= 570;
 7  int find( int x){ return x==fat[x]?x:fat[x]=find(fat[x]);}
 8  int main(){
 9     scanf( " %d ",&n);
10     memset(tmp, 0x7f, sizeof(tmp));
11     memset(ans, 0x7f, sizeof(ans));
12      for( int i= 1;i<=n;i++){
13          char s[ 5]; scanf( " %s%d ",s+ 1,&xx[i]);
14         la[i]=s[ 1]- ' A ';
15          if(!la[i]){
16             bin[xx[i]]++;
17              for( int j= 1;j<=sq;j++)tmp[j]=min(tmp[j],xx[i]%j);
18         } else  if(xx[i]<=sq)ans[i]=tmp[xx[i]];
19     }
20      for( int i= 0;i<=N;i++) if(bin[i])fat[i]=i; else fat[i]=i+ 1;
21     fat[N+ 1]=N+ 1;
22      for( int i=n;i>= 1;i--){
23          if(!la[i]){
24              if(!(--bin[xx[i]]))fat[xx[i]]=xx[i]+ 1;
25         } else  if(xx[i]>sq){
26              for( int j= 0;j<=N;j+=xx[i])
27                  if(find(j)<=N)ans[i]=min(ans[i],find(j)-j);
28         }
29     }
30      for( int i= 1;i<=n;i++) if(la[i])printf( " %d\n ",ans[i]);
31      return  0;
32 }
View Code

 

 

bzoj 4318: OSU!

 

 

题目大意

问一个长度为n, 第i为有pi的概率为1的01串期望的价值是多少。

一个01串的价值定义为它的所有极长子只含1串的长度的立方的和。

 

解题思路

尝试计算每一位对答案的贡献f(i)。 设li 为 i 前面的极长"1"串的长度

显然 f(i) = p[i] * (3 * li2 + 3 * li + 1)。

只要算出 li2 和 li 的期望, 就可以算出 f(i) 的期望了。

注意 li2 的期望并不等于 (li的期望)2 , 要单独存一个数来转移。

虽然恶意缩了缩空格,,但代码真的本来就很短很漂亮。。

ExpandedBlockStart.gif
#include <cstdio>
using  namespace std;
int n;
double ans,x,xx,x2; 
int main(){
    scanf( " %d ",&n);
     for( int i= 1;i<=n;i++){
        scanf( " %lf ",&x);
        ans+=x*( 3*x2+ 3*xx+ 1);
        x2=x*(x2+ 2*xx+ 1);
        xx=x*(xx+ 1);
    }
    printf( " %.1lf\n ",ans);
     return   0;
}
View Code

 

 

 

bzoj 4302: Hdu 5301 Buildings

 

 

题目大意

有n*m的一个矩形地面,要建公寓,现在要求公寓里的房间怎么划分,要求每间房屋都为一个矩形,而且要有一侧为矩形的边,除(x,y)位置外不能有空余,(x,y)位置不能建房间,要让房屋面积最大的那个的面积尽量的小,问最小会是多少 
(上面这段是copy下来的。。)

 

解题思路

 

构造题。首先旋转一下令 n <= m,显然, 最后答案中覆盖的块一定都是 1 * x 的

其实整个问题的答案就是覆盖了障碍点的 上, 下, 左, 右 四个点的四个块的长度。

这时候情况数就很少了, 分类讨论一下就好了。

1)(障碍物)上面的点向上, 下面的点向下, 这时候剩下的点分两种情况: 1, 全部按照 (n + 1) / 2的方式竖着排列 2, 所有左边的点向左连, 右边的点向右连(其实第2种情况更优当且仅当是一个边长为奇数的正方形且障碍点在中间)

2)(障碍物)上面的点和下面的点都向 左边和右边中更近的那一边连 , 这时候剩下的点(就是障碍物左边的所有点或者是右边的所有点)分两种情况: 1, 全部按照 (n + 1) / 2的方式竖着排列 2, 所有点都向左边/ 右边连。

好了, 其实一共只有四小类。

 

 代码还是炒鸡短。。。

 

ExpandedBlockStart.gif
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cstdio>
using  namespace std;
int n, m, x, y;
int main(){
     while(scanf( " %d%d%d%d ", &n, &m, &x, &y) != EOF){
         if(n > m) swap(n, m), swap(x, y);
         int ans = max(min((n +  1) /  2, max(y -  1, m - y -  1)), max(x -  1, n - x));
        ans = min(ans, max(min(y, m - y +  1), min((n +  1) /  2, max(y -  1, m - y))));
        printf( " %d\n ", ans);
    }
     return  0;
}
View Code

 

 

 

bzoj 4305: 数列的GCD

 

 

题目大意

给出一个长度为N的数列{a[n]},1<=a[i]<=M(1<=i<=N)。 
现在问题是,对于1到M的每个整数d,有多少个不同的数列b[1], b[2], ..., b[N],满足: 
(1)1<=b[i]<=M(1<=i<=N); 
(2)gcd(b[1], b[2], ..., b[N])=d; 
(3)恰好有K个位置i使得a[i]<>b[i](1<=i<=N)

1.  1bim
2.  gcd(b1,b2,...,bn)=d
3.  ni=1[aibi]=k

解题思路

 因为 300000 以内的数的因子个数最多也就140个, 所以这道题怎么搞一搞都可以。

 然后就是一些基本数论知识也没什么好说的。对于每一个i ,只要求出a[]中有多少个数是i的倍数。对于不是i的倍数的那些数, 贡献的方案数是 数量(n/i) , 对于是i的倍数的那些数, 贡献的是 从那么多数中选取(n-k)个数, 选出来的数每个有1种取法,其它的每个有(n/i)-1种取法。

 代码有点丑就不贴了(竟然比绝大多数代码都长简直不能忍!!!一定是我的算法太丑了QAQ)

 

 

 

bzoj 3884: 上帝与集合的正确用法

 

 

题目大意


1.  1bim
2.  gcd(b1,b2,...,bn)=d
3.  ni=1[aibi]=k

解题思路

我们都知道欧拉定理: an an mod φ(p)  mod p (gcd(a, p) = 1)

然而它竟然还有一个拓展: 

a n ≡ a n mod φ(p) +φ(p)   mod p  这个公式是始终通用的

 

然后这道题就可以随便做了。设答案为 f(x)

则 f(x) = 2 f(phi(x)) + phi(x) mod x

 

于是就可以递归地解决啦

ExpandedBlockStart.gif
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm>
 6  #define N 10000000
 7  #define ll long long
 8  using  namespace std;
 9  int t, phi[N +  5], prim[N], pp, f[N+ 5], X[ 1005], mx;
10  bool isp[N+ 5];
11  int mypow( int x,  int k,  int mod){
12      int ret =  1;
13      while(k){
14          if(k &  1) ret = (ll)ret * x % mod;
15         x = (ll)x * x % mod; k >>=  1;
16     } return ret;
17 }
18  int calc( int x){
19      if(f[x] == - 1) f[x] = mypow( 2, calc(phi[x]) + phi[x], x);
20      return f[x];
21 }
22  int main(){
23     scanf( " %d ", &t);
24      for( int i =  1; i <= t; i ++) scanf( " %d ", &X[i]), mx = max(mx, X[i]);
25      for( int i =  2; i <= mx; i ++){
26          if(!isp[i]) prim[++ pp] = i, phi[i] = i -  1;
27          for( int j =  1; j <= pp && (ll)i * prim[j] <= mx; j ++){
28             isp[i * prim[j]] =  1; phi[i * prim[j]] = phi[i] * (prim[j] -  1);
29              if(i % prim[j] ==  0) {phi[i * prim[j]] = phi[i] * prim[j];  break;}
30         }
31     }
32     memset(f, - 1, (mx +  2) *  4);
33     f[ 1] =  0;
34      for( int i =  1; i <= t; i ++) printf( " %d\n ", calc(X[i]));
35    //   system("pause");
36       return   0;
37 }
View Code

 

 

转载于:https://www.cnblogs.com/lixintong911/p/4934336.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值