不务正业也要按照基本法。。
资料参考:http://cuiqingcai.com/1319.html.
BeautifulSoup是python的一个html解析库,最新版本是bs4,但不兼容python3,所以这次是用的python2.7写法。。
导入主要用到的三个库:
import requests
from bs4 import BeautifulSoup
import re
首先要解决一下乱码问题:
由于ubuntu下的python默认解码是ascii,所以一有中文就爆炸,会出现这样的情况:
'ascii' codec can't encode characters in position 848-851: ordinal not in range(128)
于是在代码里加上这两句修改一下,当然也有其他办法,不予赘述了(天灭python2,选3保平安,网搜“python2 中文乱码”有真相!)
import sys
reload(sys)
sys.setdefaultencoding('utf8')
接下来,先爬取一个网页的html源码,这里以队友博客的一篇 题解 为例,html源码太长,可以自行查看。
然后建立一个BeautifulSoup对象:
soup = BeautifulSoup(html)
#print soup.prettify()
print soup.prettify()可以看到html源码以树状结构存储了起来。
尝试通过tag标签查找内容:
print soup.title
得到:
<title>HDU 4275 Color the Tree(哈希+树同构+组合数学+树形dp) - GODSPEED
- 博客频道 - CSDN.NET</title>
此外还有很多属性:
print soup.title.string
#HDU 4275 Color the Tree(哈希+树同构+组合数学+树形dp) - GODSPEED
# - 博客频道 - CSDN.NET
print soup.title.name
#title
...
值得注意的是,这里通过tag来查找,只返回匹配的第一个节点标签数据,如果要得到所有该标签数据,则需要遍历文档树来实现。这个结构有点像trie树,查找搜索方式很灵活,具体可参考开头提到的文档。
接下来尝试按照标签里的id值来搜索:
info = soup.select("#blog_rank")
print info
得到:
[<ul id="blog_rank">
<li>访问:<span>29690次</span></li>
<li>积分:<span>2605</span> </li>
<li>等级: <span style="position:relative;display:inline-block;z-index:1">
<img alt="" id="leveImg" src="http://c.csdnimg.cn/jifen/images/xunzhang/jianzhang/blog5.png" style="vertical-align: middle;"/>
<div id="smallTittle" style=" position: absolute; left: -24px; top: 25px; text-align: center; width: 101px; height: 32px; background-color: #fff; line-height: 32px; border: 2px #DDDDDD solid; box-shadow: 0px 2px 2px rgba (0,0,0,0.1); display: none; z-index: 999;">
<div style="left: 42%; top: -8px; position: absolute; width: 0; height: 0; border-left: 10px solid transparent; border-right: 10px solid transparent; border-bottom: 8px solid #EAEAEA;"></div>
积分:2605 </div>
</span> </li>
<li>排名:<span>第7622名</span></li>
</ul>]
除此之外还有类名查找,组合查找等。。具体内容,还是参考开头提到的博客。。
写到这里其实就差不多了。。这次比较无聊地把队友题解内容和代码给爬取了下来,虽然没什么卵用,算做练一下bs和正则表达式的运用吧。
soup = BeautifulSoup(html)
code = soup.select("#article_content")
print code #未做处理的提取内容
code = str(code[0])
code = re.compile(r'<[^>]+>').sub('', code)#去掉标签
code = code.replace('<','<')
code = code.replace('>','>')
code = code.replace('&','&') #替换html特殊字符,这里其实可以写成一个函数的。。
print code
[<div class="article_content" id="article_content">
<p><span style="font-family:SimHei; font-size:18px">题意:给出一颗n个结点的数,现在用m种颜色给每个节点染色,问不重复(通过旋转)的染色方法数有多少种。</span></p>
<p><span style="font-family:SimHei; font-size:18px">思路:这道题主要是要解决对称而导致的重复的问题,所以选择根节点时要选择树的中心,所以可以先bfs求出树的直径,如果直径上的结点个数为奇数,那么取直径的中点作为中心dfs,如果是偶数那么在两个中点位置的中间新建一个节点。</span></p>
<p><span style="font-family:SimHei; font-size:18px">用dp[i]表示以i为节点的子树中方案有多少种 ,那么对子树的形态哈希后排序,哈希值相同的子树相邻,如果某一个哈希值(即同构的子树)的子树有n个,这种子树形态的方案数为m,那么由组合数学可以得出这些子树组合起来的方案数为C(n+m-1, n),这个可以由挡板法求出,假设m-1个挡板和m个子树,从这些中选出m棵子树构成一种方案的方法有C(n+m-1, n)种。</span></p>
<p><span style="font-family:SimHei; font-size:18px">然后就是一个普通的树形dp了,因为我们是从中心开始dfs的,这样保证了不会遗漏所有同构的子树。</span></p>
<p><span style="font-family:SimHei; font-size:18px">ps:一开始哈希的素数又选搓了.....wa了一晚上加一早上........个人体会....选素数的时候不要选择太小的,最好这个素数的平方在mod的附近,这样可以保证哈希不具有太强的线性。</span></p>
<div style="top:0px">
<p></p><pre class="cpp" name="code">#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 50500;
const int MOD = 1e9+7;
const int P = 10003;
const int A = 131237;
int n, m;
vector<int> G[MAXN];
bool vis[MAXN];
int pre[MAXN], dis[MAXN];
LL inv[MAXN];
struct Node {
LL hash, ans;
bool operator < (const Node& A) const {
return hash < A.hash;
}
};
LL pow_mod(LL a, LL p, LL n) {
if(p == 0) return 1;
LL ans = pow_mod(a, p/2, n);
ans = ans * ans % n;
if(p%2 == 1) ans = ans * a % n;
return ans;
}
void init() {
for(int i = 1; i <= 50005; i++) inv[i] = pow_mod(i, MOD-2, MOD);
}
LL C(int n, int m) {
LL ans = 1;
for(int i = n-m+1; i <= n; i++) ans = ans * i % MOD;
for(int i = 1; i <= m; i++) ans = ans * inv[i] % MOD;
return ans;
}
int bfs1() {
memset(vis, 0, sizeof(vis));
queue<int> q;
q.push(1);
vis[1] = 1;
int ans = 1;
while(!q.empty()) {
int t = q.front();
q.pop();
for(int i = 0; i < G[t].size(); i++) {
int u = G[t][i];
if(vis[u]) continue;
vis[u] = 1;
q.push(u);
ans = u;
}
}
return ans;
}
int bfs2(int cur) {
memset(vis, 0, sizeof(vis));
queue<int> q;
q.push(cur);
vis[cur] = 1;
dis[cur] = 1;
int ans = cur;
while(!q.empty()) {
int t = q.front();
q.pop();
for(int i = 0; i < G[t].size(); i++) {
int u = G[t][i];
if(vis[u]) continue;
vis[u] = 1;
q.push(u);
ans = u;
pre[u] = t;
dis[u] = dis[t] + 1;
}
}
if(dis[ans] & 1) {
int tmp = dis[ans] / 2;
while(tmp--) ans = pre[ans];
return ans;
}
else {
int pos, tmp = dis[ans]/2 - 1;
while(tmp--) ans = pre[ans];
pos = pre[ans];
int root = n + 1;
G[root].push_back(ans);
G[root].push_back(pos);
for(vector<int>::iterator it = G[ans].begin(); it != G[ans].end(); it++)
if(*it == pos) {
G[ans].erase(it);
break;
}
for(vector<int>::iterator it = G[pos].begin(); it != G[pos].end(); it++)
if(*it == ans) {
G[pos].erase(it);
break;
}
//cout << ans << " " << pos << endl;
return root;
}
}
Node dfs(int cur, int fa) {
vector<Node> val;
for(int i = 0; i < G[cur].size(); i++) {
int u = G[cur][i];
if(u == fa) continue;
Node tmp = dfs(u, cur);
val.push_back(tmp);
}
sort(val.begin(), val.end());
Node ret;
ret.hash = A, ret.ans = 1;
int sz = val.size();
for(int i = 0; i < sz;) {
int j = i;
while(j<sz && val[j].hash==val[i].hash) {
ret.hash *= P;
ret.hash ^= val[i].hash;
ret.hash %= MOD;
j++;
}
ret.ans *= C(j-i+val[i].ans-1, j-i);
ret.ans %= MOD;
i = j;
//cout << val[i].ans << " " << cur << " " << i << endl;
}
if(cur <= n) ret.ans = ret.ans * m % MOD;
//cout << ret.ans << endl;;
return ret;
}
int main() {
//freopen("input.txt", "r", stdin);
init();
while(scanf("%d%d", &n, &m) == 2) {
for(int i = 1; i <= n+1; i++) G[i].clear();
for(int i = 1, u, v; i < n; i++) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
int tmp = bfs1();
int root = bfs2(tmp);
Node ans = dfs(root, 0);
cout << ans.ans << endl;
}
return 0;
}
</pre><br/>
</div>
<div style="padding-top:20px">
<p style="font-size:12px;">版权声明:本文为Godspeed原创文章,未经博主允许不得转载。</p>
</div>
</div>]
题意:给出一颗n个结点的数,现在用m种颜色给每个节点染色,问不重复(通过旋转)的染色方法数有多少种。
思路:这道题主要是要解决对称而导致的重复的问题,所以选择根节点时要选择树的中心,所以可以先bfs求出树的直径,如果直径上的结点个数为奇数,那么取直径的中点作为中心dfs,如果是偶数那么在两个中点位置的中间新建一个节点。
用dp[i]表示以i为节点的子树中方案有多少种 ,那么对子树的形态哈希后排序,哈希值相同的子树相邻,如果某一个哈希值(即同构的子树)的子树有n个,这种子树形态的方案数为m,那么由组合数学可以得出这些子树组合起来的方案数为C(n+m-1, n),这个可以由挡板法求出,假设m-1个挡板和m个子树,从这些中选出m棵子树构成一种方案的方法有C(n+m-1, n)种。
然后就是一个普通的树形dp了,因为我们是从中心开始dfs的,这样保证了不会遗漏所有同构的子树。
ps:一开始哈希的素数又选搓了.....wa了一晚上加一早上........个人体会....选素数的时候不要选择太小的,最好这个素数的平方在mod的附近,这样可以保证哈希不具有太强的线性。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 50500;
const int MOD = 1e9+7;
const int P = 10003;
const int A = 131237;
int n, m;
vector<int> G[MAXN];
bool vis[MAXN];
int pre[MAXN], dis[MAXN];
LL inv[MAXN];
struct Node {
LL hash, ans;
bool operator < (const Node& A) const {
return hash < A.hash;
}
};
LL pow_mod(LL a, LL p, LL n) {
if(p == 0) return 1;
LL ans = pow_mod(a, p/2, n);
ans = ans * ans % n;
if(p%2 == 1) ans = ans * a % n;
return ans;
}
void init() {
for(int i = 1; i <= 50005; i++) inv[i] = pow_mod(i, MOD-2, MOD);
}
LL C(int n, int m) {
LL ans = 1;
for(int i = n-m+1; i <= n; i++) ans = ans * i % MOD;
for(int i = 1; i <= m; i++) ans = ans * inv[i] % MOD;
return ans;
}
int bfs1() {
memset(vis, 0, sizeof(vis));
queue<int> q;
q.push(1);
vis[1] = 1;
int ans = 1;
while(!q.empty()) {
int t = q.front();
q.pop();
for(int i = 0; i < G[t].size(); i++) {
int u = G[t][i];
if(vis[u]) continue;
vis[u] = 1;
q.push(u);
ans = u;
}
}
return ans;
}
int bfs2(int cur) {
memset(vis, 0, sizeof(vis));
queue<int> q;
q.push(cur);
vis[cur] = 1;
dis[cur] = 1;
int ans = cur;
while(!q.empty()) {
int t = q.front();
q.pop();
for(int i = 0; i < G[t].size(); i++) {
int u = G[t][i];
if(vis[u]) continue;
vis[u] = 1;
q.push(u);
ans = u;
pre[u] = t;
dis[u] = dis[t] + 1;
}
}
if(dis[ans] & 1) {
int tmp = dis[ans] / 2;
while(tmp--) ans = pre[ans];
return ans;
}
else {
int pos, tmp = dis[ans]/2 - 1;
while(tmp--) ans = pre[ans];
pos = pre[ans];
int root = n + 1;
G[root].push_back(ans);
G[root].push_back(pos);
for(vector<int>::iterator it = G[ans].begin(); it != G[ans].end(); it++)
if(*it == pos) {
G[ans].erase(it);
break;
}
for(vector<int>::iterator it = G[pos].begin(); it != G[pos].end(); it++)
if(*it == ans) {
G[pos].erase(it);
break;
}
//cout << ans << " " << pos << endl;
return root;
}
}
Node dfs(int cur, int fa) {
vector<Node> val;
for(int i = 0; i < G[cur].size(); i++) {
int u = G[cur][i];
if(u == fa) continue;
Node tmp = dfs(u, cur);
val.push_back(tmp);
}
sort(val.begin(), val.end());
Node ret;
ret.hash = A, ret.ans = 1;
int sz = val.size();
for(int i = 0; i < sz;) {
int j = i;
while(j<sz && val[j].hash==val[i].hash) {
ret.hash *= P;
ret.hash ^= val[i].hash;
ret.hash %= MOD;
j++;
}
ret.ans *= C(j-i+val[i].ans-1, j-i);
ret.ans %= MOD;
i = j;
//cout << val[i].ans << " " << cur << " " << i << endl;
}
if(cur <= n) ret.ans = ret.ans * m % MOD;
//cout << ret.ans << endl;;
return ret;
}
int main() {
//freopen("input.txt", "r", stdin);
init();
while(scanf("%d%d", &n, &m) == 2) {
for(int i = 1; i <= n+1; i++) G[i].clear();
for(int i = 1, u, v; i < n; i++) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
int tmp = bfs1();
int root = bfs2(tmp);
Node ans = dfs(root, 0);
cout << ans.ans << endl;
}
return 0;
}
版权声明:本文为Godspeed原创文章,未经博主允许不得转载。
另一位队友的:(http://www.cnblogs.com/Cw-trip/p/4898112.html
import requests
from bs4 import BeautifulSoup
import re
import sys
reload(sys)
sys.setdefaultencoding('utf8')
url = 'http://www.cnblogs.com/Cw-trip/p/4898112.html'
headers = {'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:41.0) Gecko/20100101 Firefox/41.0'}
html = requests.get(url, headers=headers).content
soup = BeautifulSoup(html)
code = soup.select("#cnblogs_post_body")
code = str(code[0])
code = re.compile(r'<[^>]+>').sub('', code)
code = code.replace('<','<')
code = code.replace('>','>')
code = code.replace('&','&') #
print code
题目:给出一个数列,要求快速查询区间lr内相同数字的对数。
思路:对于每次询问暴力跑,但是我们注意到由于可以复用之前的结果,所以不同的计算顺序计算量可能不同,直观上来说,两个查询点的曼哈顿距离越短,需要计算的量就越小。于是我们可以找出一个最佳计算顺序,就是平面点阵的最短哈密顿回路。由于这是np的,所以可以用最小曼哈顿生成树代替。再简化一下,可以使用分快处理的方法得到比较快的速度。
这就是所谓的莫队算法。
/*
* @author: Cwind
*/
///#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <queue>
#include <stack>
#include <functional>
#include <set>
#include <cmath>
using namespace std;
#define IOS std::ios::sync_with_stdio (false);std::cin.tie(0)
#define pb push_back
#define PB pop_back
#define bk back()
#define fs first
#define se second
#define sq(x) (x)*(x)
#define eps (1e-7)
#define IINF (1<<29)
#define LINF (1ll<<59)
#define INF (1000000000)
#define FINF (1e3)
#define clr(x) memset((x),0,sizeof (x))
#define cp(a,b) memcpy((a),(b),sizeof (a))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<int,int> P;
const int maxn=5e4+3000;
struct Q{
int l,r;
int id;
}q[maxn];;
bool cmp1(const Q &a,const Q &b){return a.r<b.r;}
vector<Q> B[50];
int n,m;
int c[maxn];
ll a[maxn];
ll ans[maxn][2];
void solve(){
for(int i=1;i<=m;i++) B[q[i].l/1001].pb(q[i]);
for(int i=0;i<50;i++) sort(B[i].begin(),B[i].end(),cmp1);
ll ax=0,ay=0;
int l=1,r=1;
a[c[1]]++;
for(int i=0;i<50;i++){
for(int j=0;j<B[i].size();j++){
int tl=B[i][j].l,tr=B[i][j].r;
for(int k=r;k>tr;k--){ax-=a[c[k]]-1;a[c[k]]--;ay-=k-l;}
for(int k=r+1;k<=tr;k++){ax+=a[c[k]];a[c[k]]++;ay+=k-l;}
for(int k=l;k<tl;k++){a[c[k]]--;ax-=a[c[k]];ay-=tr-k;}
for(int k=l-1;k>=tl;k--){ax+=a[c[k]];a[c[k]]++;ay+=tr-k;}
l=tl,r=tr;
ll dd=__gcd(ax,ay);
int id=B[i][j].id;
ans[id][0]=ax/dd;
ans[id][1]=ay/dd;
if(ax==0) ans[id][1]=1;
}
}
}
int main(){
freopen("/home/slyfc/CppFiles/in","r",stdin);
cin>>n>>m;
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
for(int i=1;i<=m;i++){
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
solve();
for(int i=1;i<=m;i++) printf("%lld/%lld\n",ans[i][0],ans[i][1]);
return 0;
}
View Code
于是我大概知道了我们的原创博客是怎样被那些恶心的网站转走的,但却无能为力。