---------9.7
cf 575 h
http://codeforces.com/problemset/problem/575/H
题意不懂怎么描述诶,大意就是
先有一颗满二叉树,然后从根到叶子的路上有n条边染成红色,n条边染成蓝色,问满足这样条件的树有多少个节点
想到一点点,就是每次扩展下一层的时候,用本来应该满足满二叉树的节点数减去不合法的节点数---
可是不懂算这里------
本来按照一颗正常的二叉树
每扩展一层,节点数乘以2
但是因为有n的限制
就不会增加那么多个的节点
在前n层,是没有限制的,红色蓝色任意选
但是到第n+1层,因为肯定有两条路是已经填完红色,蓝色的
所以 它增加的节点数 为 ( C(n+1,n) - C(n,n) ) *2
然后假设现在走到深度为 K + 1
它比上一层增加的节点数 为 (C(K+1,n) - C(K,n))*2
再一层层的算
----------------话说不懂组合数取模,先抄了个lucas,T了
后来----抄了一个预处理的---------还是不懂这样算组合数---------------
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 7 typedef long long ll; 8 const int MAXN = 2000010; 9 const ll mod = 1e9 + 7; 10 11 int N; 12 ll fac[MAXN + 10],afac[MAXN + 10]; 13 14 ll Q_pow(ll x,ll y){ 15 ll res = 1; 16 x %= mod; 17 while(y){ 18 if(y & 1) res = res * x % mod; 19 x = x * x % mod; 20 y >>= 1; 21 } 22 return res; 23 } 24 25 void Pre(){ 26 fac[0] = 1; 27 for(int i = 1; i <= MAXN; ++i) fac[i] = fac[i - 1] * (ll)i % mod; 28 afac[MAXN] = Q_pow(fac[MAXN],mod - 2); 29 for(int i = MAXN; i >= 1; --i) afac[i - 1] = afac[i] * i % mod; 30 } 31 32 ll C(ll n,ll m){ 33 if(m > n) return 0; 34 return fac[n] * afac[n - m] % mod * afac[m] % mod; 35 } 36 37 int main(){ 38 Pre(); 39 scanf("%d",&N); 40 ll ans = Q_pow(2,N+1)-1; 41 ll cur = Q_pow(2,N); 42 ll tmp = cur; 43 for(int i = N+1;i <= 2*N;i++){ 44 ll shao = 2LL*((C(i-1,N) - C(i-2,N) + mod) % mod) %mod; 45 // printf("shao = %I64d\n",shao); 46 tmp = (tmp-shao + mod)%mod; 47 cur = cur + tmp; 48 ans = (ans + cur) %mod; 49 tmp = 2LL*tmp%mod; 50 } 51 printf("%I64d\n",ans); 52 return 0; 53 }
新的一周----加油--------------------------
cf 2B
http://codeforces.com/problemset/problem/2/B
这题目的编号 >_<
不会做------------
先想的是 dp[i][j]表示走到第i行,第j列的0最少有多少个
可是转移不出来
后来,题解是这样做的
因为答案所在的路径要不然是含有2的个数最少的,要不然是含有5的个数最少的
画几个例子就懂了---
然后就按照2的个数少dp一次,按照5的个数少dp一次
不过要注意给出的矩阵中本身含有0的情况
如果矩阵中含有0,就要用1和 dp2 ,dp5的答案去比较,1更小的话,直接构造出一条走0的路线
还是不懂路径打印----在cf上翻了一份------
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 7 const int INF = (1<<30)-1; 8 const int maxn = 1005; 9 int f[maxn][maxn][2],g[maxn][maxn][2]; 10 int n,x,pos; 11 12 void print(int x,int y){ 13 if(x == 1 && y == 1) return; 14 if(g[x][y][pos]) print(x-1,y),printf("D"); 15 else print(x,y-1),printf("R"); 16 } 17 18 int main(){ 19 scanf("%d",&n); 20 memset(f,0,sizeof(f)); 21 memset(g,0,sizeof(g)); 22 23 for(int i = 2;i <= n;i++) 24 f[i][0][0] = f[i][0][1] = f[0][i][1] = f[0][i][0] = INF; 25 26 for(int i = 1;i <= n;i++){ 27 for(int j = 1;j <= n;j++){ 28 int k; 29 scanf("%d",&k); 30 if(k == 0) x = i; 31 while(k){ 32 if(k%2 != 0) break; 33 k = k/2; 34 f[i][j][0]++; 35 } 36 while(k){ 37 if(k%5 != 0) break; 38 k = k/5; 39 f[i][j][1]++; 40 } 41 for(int k = 0;k < 2;k++){ 42 if(f[i-1][j][k] < f[i][j-1][k]) { 43 f[i][j][k] += f[i-1][j][k]; 44 g[i][j][k] = 1;//D 45 } 46 else{ 47 f[i][j][k] += f[i][j-1][k]; 48 g[i][j][k] = 0; 49 } 50 } 51 } 52 } 53 54 // for(int i = 1;i <= n;i++){ 55 // for(int j = 1;j <= n;j++){ 56 // for(int k = 1;k < 2;k++) 57 // printf("f[%d][%d][%d] = %d g[%d][%d][%d] = %d\n",i,j,k,f[i][j][k],i,j,k,g[i][j][k]); 58 // } 59 // } 60 61 if(f[n][n][0] < f[n][n][1]) pos = 0; 62 else pos = 1; 63 64 int ans = min(f[n][n][0],f[n][n][1]); 65 if(x && (ans > 1)){ 66 puts("1"); 67 for(int i = 2;i <= x;i++) printf("D"); 68 for(int i = 2;i <= n;i++) printf("R"); 69 for(int i = x+1;i <= n;i++) printf("D"); 70 } 71 else{ 72 printf("%d\n",ans); 73 print(n,n); 74 } 75 76 return 0; 77 }
cf 463 d
http://codeforces.com/problemset/problem/463/D
求k个串的最长公共子序列
不懂做----
不过话说还是清醒的认识到----不能用第一个和第二个的最长公共子序列再去求第三个第四个的-------呜呜呜
应该这样---
如果对于一个数 i ,对于所有行的 j ,i 的位置都比 j 的靠前,那么 i 到 j 连一条边
这样,就转化成了一个有向无环图,因为自己不可能连向自己
然后再求 DAG 上的最长路
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 8 const int maxn = 1005; 9 int n,k; 10 int a[maxn][maxn]; 11 int pos[maxn][maxn]; 12 vector<int> g[maxn]; 13 int dp[maxn]; 14 15 //wei ziji jiayou >_< 16 17 int dfs(int u){ 18 if(dp[u]) return dp[u]; 19 for(int i = 0;i < g[u].size();i++){ 20 int v = g[u][i]; 21 dp[u] = max(dp[u],dfs(v)); 22 } 23 return dp[u] = dp[u] + 1; 24 } 25 26 27 int main(){ 28 while(scanf("%d %d",&n,&k) != EOF){ 29 memset(pos,0,sizeof(pos)); 30 for(int i = 1;i <= n;i++) g[i].clear(); 31 32 for(int i = 1;i <= k;i++){ 33 for(int j = 1;j <= n;j++){ 34 scanf("%d",&a[i][j]); 35 pos[a[i][j]][i] = j; 36 } 37 } 38 39 int ok = 1; 40 for(int i = 1;i <= n;i++){ 41 for(int j = 1;j <= n;j++){ 42 ok = 1; 43 for(int l = 1;l <= k;l++){ 44 if(pos[i][l] >= pos[j][l]){ 45 ok = 0; 46 break; 47 } 48 } 49 if(ok) g[i].push_back(j); 50 } 51 } 52 53 int ans = -1; 54 memset(dp,0,sizeof(dp)); 55 for(int i = 1;i <= n;i++) { 56 ans = max(ans,dfs(i)); 57 // printf("dp[%d] = %d ans =%d\n",i,dp[i],ans); 58 } 59 printf("%d\n",ans); 60 } 61 return 0; 62 }
学KMP中----加上弄协会的事情-----
哎--------------------------------------
加油拉
---------9.8
poj 3461 Oulipo
裸的KMP
因为做cf上的一道题目不会做---
搜题解发现好多用的是KMP
所以滚去学了一发
字符串第一位从1开始编号
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 8 const int maxn = 10005; 9 char a[100*maxn],b[maxn]; 10 int p[maxn]; 11 int lena,lenb; 12 13 void Get_p(){ 14 p[1] = 0; 15 int j = 0; 16 for(int i = 2;i <= lenb;i++){ 17 while(j > 0 && b[j+1] != b[i]) j = p[j]; 18 if(b[j+1] == b[i]) j++; 19 p[i] = j; 20 } 21 } 22 23 void KMP(){ 24 Get_p(); 25 int ans = 0; 26 int j = 0; 27 for(int i = 1;i <= lena;i++){ 28 while(j > 0 && b[j+1] != a[i] ) j = p[j]; 29 if(b[j+1] == a[i]) j++; 30 if(j == lenb){ 31 j = p[j]; 32 ans++; 33 } 34 } 35 printf("%d\n",ans); 36 } 37 38 int main(){ 39 int T; 40 scanf("%d",&T); 41 while(T--){ 42 scanf("%s",b+1); lenb = strlen(b+1); 43 scanf("%s",a+1); lena = strlen(a+1); 44 45 KMP(); 46 47 //for(int i = 1;i <= lenb;i++) 48 //printf("p[%d] = %d\n",i,p[i]); 49 } 50 return 0; 51 }
补一个字符串从0开始编号的
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 8 const int maxn = 10005; 9 char a[100*maxn],b[maxn]; 10 int p[maxn]; 11 int lena,lenb; 12 13 void Get_p(){ 14 p[0] = -1; 15 int j = -1; 16 for(int i = 1;i < lenb;i++){ 17 while(j >= 0 && b[j+1] != b[i]) j = p[j]; 18 if(b[j+1] == b[i]) j++; 19 p[i] = j; 20 } 21 } 22 23 void KMP(){ 24 Get_p(); 25 int ans = 0; 26 int j = -1; 27 for(int i = 0;i < lena;i++){ 28 while(j >= 0 && b[j+1] != a[i] ) j = p[j]; 29 if(b[j+1] == a[i]) j++; 30 if(j == lenb-1){ 31 j = p[j]; 32 ans++; 33 } 34 } 35 printf("%d\n",ans); 36 } 37 38 int main(){ 39 int T; 40 scanf("%d",&T); 41 while(T--){ 42 scanf("%s",b); lenb = strlen(b); 43 scanf("%s",a); lena = strlen(a); 44 45 KMP(); 46 47 //for(int i = 1;i <= lenb;i++) 48 //printf("p[%d] = %d\n",i,p[i]); 49 } 50 return 0; 51 }
cf 404 c
http://codeforces.com/contest/404/problem/C
将高度排序,构造树的过程中记录下度数,就可以了
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 8 int n,k; 9 const int maxn = 100005; 10 int d[maxn]; 11 int du[maxn]; 12 vector<int> h[maxn]; 13 vector<int> g[maxn]; 14 15 struct node{ 16 int id; 17 int d; 18 }a[maxn]; 19 20 int cmp(node n1,node n2){ 21 return n1.d < n2.d; 22 } 23 24 void solve(){ 25 sort(a+1,a+n+1,cmp); 26 27 memset(du,0,sizeof(du)); 28 int c = 0; 29 int root; 30 for(int i = 1;i <= n;i++){ 31 if(a[i].d == 0) { 32 c++; 33 root = a[i].id; 34 } 35 } 36 if(c == 0 || c > 1) { 37 puts("-1"); 38 return; 39 } 40 41 for(int i = 1;i <= n;i++){ 42 h[a[i].d].push_back(a[i].id); 43 } 44 45 for(int i = 2;i <= n;i++){ 46 int l = a[i].d; 47 int r = a[i].id; 48 if(h[l-1].size() == 0){ 49 puts("-1"); 50 return; 51 } 52 int ok = 0; 53 for(int j = 0;j < h[l-1].size();j++){ 54 int v = h[l-1][j]; 55 // printf("i = %d v = %d r = %d\n",i,v,r); 56 if(du[v] >= k) continue; 57 else{ 58 g[v].push_back(r); 59 du[v]++; 60 du[r]++; 61 ok = 1; 62 break; 63 } 64 } 65 if(ok == 0){ 66 puts("-1"); 67 return; 68 } 69 } 70 int res = 0; 71 for(int i = 1;i <= n;i++) res += g[i].size(); 72 printf("%d\n",res); 73 for(int i = 1;i <= n;i++){ 74 for(int j = 0;j < g[i].size();j++){ 75 int v = g[i][j]; 76 printf("%d %d\n",i,v); 77 } 78 } 79 } 80 81 int main(){ 82 scanf("%d %d",&n,&k); 83 for(int i = 1;i <= n;i++) g[i].clear(),h[i].clear(); 84 85 for(int i = 1;i <= n;i++) { 86 scanf("%d",&a[i].d); 87 a[i].id = i; 88 } 89 solve(); 90 return 0; 91 }
话说做这题---有种页面找不到了的错觉------------->_<
话说做不来题目的时候,就画画,现在爪机里面攒了好多画了----还是觉得画得好的才拍照留下来-----
话说是有好多好多不会做的题目---------------------
该滚了---
哈哈哈哈---昨天买了速写本--决定做不来题目的时候就在本子上画画---------------------------------------------
加油加油加油
cf 505 c
http://codeforces.com/problemset/problem/505/C
好有缘分的两道题目~~~~
还是没有想出来啊---
想到的还是一维的,dp[i] 表示走到i的时候能够拿到的最多的宝石的数目,可是步数就不懂转移了
其实---是这样的-----
开二维的数组
dp[i][j]表示到达 i 的前一步跳了 j 步能够拿到的最多的宝石数
可是30000*3000就开不下了--
然后考虑相当于一直向某一个方向跳跃的情况
d-1, d-2,d-3,------,d-x
所以有 x*(x-1)/2 = 30000
解出来 x = 245
然后这样跳也是
d+1, d+2, d+3,------,d+x
x = 245
然后因为记忆化搜索的时候有要减去的情况(d-1,d-2-----d-245)
所以给它加上300或者400这些都可以
话说是这样理解得么~~~~~~~~~~~~~~~
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 7 int dp[30005][1000]; 8 int d,n,maxn; 9 int a[30005]; 10 11 int dfs(int p,int pre){ 12 if(p > maxn) return 0; 13 if(dp[p][pre-d+300] > -1) return dp[p][pre-d+300]; 14 int res = 0; 15 if(pre > 1) res = max(res,dfs(p+pre-1,pre-1)); 16 res = max(res,dfs(p+pre,pre)); 17 res = max(res,dfs(p+pre+1,pre+1)); 18 return dp[p][pre-d+300] = res + a[p]; 19 } 20 21 int main(){ 22 memset(dp,-1,sizeof(dp)); 23 memset(a,0,sizeof(a)); 24 scanf("%d %d",&n,&d); 25 maxn = -1; 26 for(int i = 1;i <= n;i++){ 27 int x; 28 scanf("%d",&x); maxn = max(maxn,x); 29 a[x]++; 30 } 31 printf("%d\n",dfs(d,d)); 32 33 return 0; 34 }
---------9.9
cf 126 b
http://codeforces.com/problemset/problem/126/B
KMPKMPKMPKMPKMP------
给出一个字符串,找出最长的子串,并且保证这个子串既是前缀,又是后缀,又在中间
没有想出来啊啊啊啊啊-----
最开始没有学KMP的时候---
是这样想的---
啊---我去二分一下后缀的起始端点,然后判断一下是否等于前缀还有中间是不是含有这个后缀就可以了--
nlogn---刚好----
可是---这个是没有单调性的,这一次的起始的端点不行,那下一次的端点在它的左边还是右边呢---不能确定---
所以不行----居然还过了10个样例------
然后--滚去学了一发KMP之后---
又愚蠢地这样想----
啊---去枚举一下前缀---看前缀在串里出现的次数是不是大于等于3,再维护合法的最长的前缀就好啦----
可是,,这样n^2 ,没有打
于是看题解了---------------------------------------------------------------------
发现还是p数组理解得不够好
可以写出有解的两种情况
1.
i f i x e d f i x f i x
p[i] 0 0 0 0 0 1 2 3 1 2 3
不重合的三段
只要在前面找到一次p[n]就可以了
2.
p a p a p a p a p
p[i] 0 0 1 2 3 4 5 6 7
有重合的三段
1 ---5
2 ---7
3----9
如果p[p[n]] == 0就成不了三段,就没有解了
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 8 const int maxn = 1000005; 9 char a[100*maxn],b[maxn]; 10 int p[maxn]; 11 int lena,lenb; 12 13 //wei ziji jiayou >_< 14 15 void Get_p(){ 16 p[1] = 0; 17 int j = 0; 18 for(int i = 2;i <= lenb;i++){ 19 while(j > 0 && b[j+1] != b[i]) j = p[j]; 20 if(b[j+1] == b[i]) j++; 21 p[i] = j; 22 } 23 } 24 25 void solve(){ 26 if(p[lenb] == 0){ 27 puts("Just a legend"); 28 return; 29 } 30 for(int i = 2;i < lenb;i++){ 31 // printf("p[%d] = %d p[lenb] = %d\n",i,p[i],p[lenb]); 32 if(p[i] == p[lenb]){ 33 for(int j = i-p[i]+1;j <= i;j++) printf("%c",b[j]); 34 printf("\n"); 35 return; 36 } 37 } 38 39 if(p[p[lenb]] == 0){ 40 puts("Just a legend"); 41 return; 42 } 43 for(int i = p[lenb]-p[p[lenb]]+1;i <= p[lenb];i++) printf("%c",b[i]); 44 printf("\n"); 45 } 46 47 int main(){ 48 while(scanf("%s",b+1) != EOF){ 49 memset(p,0,sizeof(p)); 50 lenb = strlen(b+1); 51 Get_p(); 52 53 //for(int i = 1;i <= lenb;i++) 54 //printf("p[%d] = %d\n",i,p[i]); 55 solve(); 56 } 57 return 0; 58 }
在下雨------
cf 107 a
http://codeforces.com/problemset/problem/107/A
从入度为0且没有访问过的点开始搜,维护每一条链的最小值
m等于0的时候,要输出0,而且必须是一条链,这条链上的点必须大于等于2个
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 #define MP(a,b) make_pair(a,b) 7 using namespace std; 8 9 const int INF = (1<<30)-1; 10 const int maxn = 1005; 11 typedef pair<int,int> pii; 12 vector<int> c[maxn]; 13 int first[maxn],ecnt; 14 int n,m,cnt; 15 int in[maxn],out[maxn],vis[maxn],w[maxn]; 16 17 struct Edge{ 18 int u,v,next,w; 19 }e[maxn]; 20 21 struct node{ 22 int x,y,w; 23 }ans[maxn]; 24 25 int cmp(node n1,node n2){ 26 return n1.x < n2.x; 27 } 28 29 void init(){ 30 ecnt = 0; 31 memset(first,-1,sizeof(first)); 32 } 33 34 void add_edges(int u,int v,int w){ 35 e[ecnt].u = u; 36 e[ecnt].v = v; 37 e[ecnt].w = w; 38 e[ecnt].next = first[u]; 39 first[u] = ecnt++; 40 } 41 42 void dfs(int u){ 43 vis[u] = 1; 44 if(in[u] == 0) ans[cnt].x = u; 45 if(out[u] == 0) ans[cnt].y = u; 46 for(int i = first[u];~i;i = e[i].next){ 47 int v = e[i].v; 48 ans[cnt].w = min(ans[cnt].w,e[i].w); 49 if(vis[v]) continue; 50 dfs(v); 51 } 52 } 53 54 void solve(){ 55 int c1 = 0; 56 for(int i = 1;i <= n;i++){ 57 if(in[i] + out[i] == 2) c1++; 58 } 59 if(c1 == n || m == 0){ 60 puts("0"); 61 return; 62 } 63 64 65 memset(vis,0,sizeof(vis)); 66 for(int i = 1;i <= n;i++) ans[i].w = INF; 67 68 cnt = 1; 69 for(int i = 1;i <= n;i++){ 70 if(!vis[i] && in[i] == 0) dfs(i),cnt++; 71 } 72 73 // for(int i = 1;i < cnt;i++){ 74 // printf("a[%d].x = %d a[%d].y = %d a[%d].w = %d\n",i,ans[i].x,i,ans[i].y,i,ans[i].w); 75 // } 76 77 sort(ans+1,ans+cnt,cmp); 78 for(int i = 1;i < cnt;i++) if(ans[i].x == ans[i].y) cnt--; 79 80 printf("%d\n",cnt-1); 81 82 for(int i = 1;i < cnt;i++){ 83 printf("%d %d %d\n",ans[i].x,ans[i].y,ans[i].w); 84 } 85 86 } 87 88 int main(){ 89 while(scanf("%d %d",&n,&m) != EOF){ 90 init(); 91 memset(in,0,sizeof(in));memset(out,0,sizeof(out)); 92 for(int i = 1;i <= m;i++){ 93 int u,v,w; 94 scanf("%d %d %d",&u,&v,&w); 95 out[u]++;in[v]++; 96 add_edges(u,v,w); 97 } 98 solve(); 99 } 100 return 0; 101 }
cf 128 a
http://codeforces.com/contest/128/problem/A
外面国防生唱歌好带感啊---
我做题做得好忧郁啊---
bfs状态是三维的没想到
倒是把图按照时间弄成三维的,不知道咋想的,然后vis就标记不对啊,然后就一直跑啊-----飞一样的----
然后---wa4了---看数据还想不通为什么这个答案--(后来才发现是可以对角线走的)
于是看题解吧--
三维的bfs,vis再加一个时间就可以了---
然后写了一直wa10---
后来读题才发现,,,他还可以停留在原地----
不说了,桑心----555555555555555555555
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 8 char g[10][10]; 9 int vis[10][10][10]; 10 int dir[9][2] = {0,0,1,0,1,1,0,1,-1,1,-1,0,-1,-1,0,-1,1,-1}; 11 12 struct node{ 13 int x,y,t; 14 }; 15 16 int ok(int x,int y,int t){ 17 if(x <= 0 || x > 8 || y <= 0 || y > 8 || g[x-t][y] == 'S') return 0; 18 return 1; 19 } 20 21 bool bfs(){ 22 memset(vis,0,sizeof(vis)); 23 queue<node> q; 24 q.push(node{8,1,0}); 25 26 while(!q.empty()){ 27 node u = q.front();q.pop(); 28 29 if(u.t > 8) return true; 30 if(g[u.x-u.t][u.y] == 'S') continue; 31 //printf("u.x = %d u.y = %d u.t = %d\n",u.x,u.y,u.t); 32 for(int i = 0;i < 9;i++){ 33 int xx = u.x + dir[i][0]; 34 int yy = u.y + dir[i][1]; 35 if(!ok(xx,yy,u.t)) continue; 36 if(!vis[xx][yy][u.t+1]){ 37 vis[xx][yy][u.t+1] = 1; 38 q.push(node{xx,yy,u.t+1}); 39 } 40 } 41 } 42 return false; 43 } 44 45 int main(){ 46 // freopen("in.txt","r",stdin); 47 // freopen("out.txt","w",stdout); 48 for(int i = 1;i <= 8;i++){ 49 for(int j = 1;j <= 8;j++){ 50 cin >> g[i][j]; 51 } 52 } 53 if(bfs()) puts("WIN"); 54 else puts("LOSE"); 55 return 0; 56 }
---------9.10
昨晚不想做题,看到别人博客有写生成树计数
于是滚去学了一下 >_<
给出一个无向图
它的度数矩阵记为 d[][]
当 i = j 的时候,d[i][j] 为 vi的度数
当 i != j 的时候,d[i][j]为0
它的邻接矩阵记为 a[][]
当i = j 的时候, a[i][j] = 0
当 i!= j的时候,如果i到j有边的话,a[i][j] = a[j][i] = 1
它的Kirchhoff矩阵等于 == d - a
然后无向图的生成树的个数为 它的Kirchhoff矩阵的任意 n-1 阶主子式的行列式绝对值
看证明没有看懂---------
抄一个模板
spoj 104
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 8 typedef long long LL; 9 const int MAXN = 15; 10 LL g[MAXN][MAXN]; 11 int n,m; 12 int d[MAXN]; 13 14 LL Det(LL A[MAXN][MAXN],int n){ 15 LL res = 1; 16 for(int i = 1; i <= n; ++i){ 17 for(int j = i + 1; j <= n; ++j){ 18 while(A[j][i]){ 19 LL t = A[i][i] / A[j][i]; 20 for(int k = i; k <= n; ++k) 21 A[i][k] = (A[i][k] - A[j][k] * t); 22 for(int k = i; k <= n; ++k) 23 swap(A[i][k],A[j][k]); 24 res = -res; //行列式换行,值取反 25 } 26 } 27 if(!A[i][i]) return 0; 28 res = res * A[i][i] ; 29 } 30 if(res < 0) res = -res; 31 return res; 32 } 33 34 int main(){ 35 int T; 36 scanf("%d",&T); 37 while(T--){ 38 memset(g,0,sizeof(g)); 39 memset(d,0,sizeof(d)); 40 scanf("%d %d",&n,&m); 41 for(int i = 1;i <= m;i++){ 42 int u,v; 43 scanf("%d %d",&u,&v); 44 g[u][v] = g[v][u] = -1; 45 d[u]++;d[v]++; 46 } 47 for(int i = 1;i <= n;i++) g[i][i] = d[i];//g为原图的Kirchhoff矩阵 48 printf("%lld\n",Det(g,n-1));//对矩阵g求一次n-1阶主子式的行列式绝对值 49 } 50 return 0; 51 }
cf 518 d
http://codeforces.com/contest/518/problem/D
呜呜呜---第一次自己想出dp来,虽然是一道简单的概率dp,,,感动哭
加油---------
dp[i][j]表示第i秒有j个人的概率,然后递推的时候注意一下边界就可以了
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 8 const int maxn = 2005; 9 double dp[maxn][maxn]; 10 int n,t; 11 double p; 12 13 int main(){ 14 while(scanf("%d %lf %d",&n,&p,&t) != EOF){ 15 memset(dp,0,sizeof(dp)); 16 dp[1][0] = 1-p; dp[1][1] = p; 17 18 for(int i = 2;i <= t;i++){ 19 for(int j = 0;j <= n;j++){ 20 if(j > i) continue; 21 if(j-1 >= 0) dp[i][j] += dp[i-1][j-1]*p; 22 if(j == n) dp[i][j] += dp[i-1][j]; 23 if(j < n) dp[i][j] += dp[i-1][j]*(1-p); 24 //printf("dp[%d][%d] = %lf\n",i,j,dp[i][j]); 25 } 26 } 27 double res = 0; 28 for(int i = 1;i <= n;i++) { 29 res += dp[t][i]*i; 30 // printf("res = %lf\n",res); 31 } 32 printf("%lf\n",res); 33 } 34 return 0; 35 }
cf 219 d
给出一个有向图,可以修改边的方向,使得能够有点能够到达所有的其他点
问修改的最小的边的数量,并且输出满足这个条件的所有的点
想了好久,写了一个统计每个点包含点的个数的版本----wa4----
简直一点边都没有沾到----
应该是这样的http://www.cnblogs.com/Running-Time/p/4663538.html
搜的时候,标记顺着的方向,就是u ---> v的边权为0,逆着的方向的边权为1
(学习了,完全没有想到过这种,还在想,如果把它添加成双向的边,那就怎么搜都是0了,,,挫爆了---)
第一次dfs 以1为根,统计以1为根的时候需要修改的边数
第二次dfs,从上至下搜出每个节点分别需要修改的边数
最开始没有看懂---
后来用自己wa的那组数据画了一下,就好懂多了---
8 1 2 3 2 4 3 4 5 6 5 6 7 8 7
还搜到一篇言简意赅的题解----啊,说这个是很大众的树型dp----然后dfs一下下就好啦---
滚了----555555555555555
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 8 const int maxn = 200005; 9 int n,ecnt; 10 int first[maxn],vis[maxn],dp[maxn]; 11 12 struct Edge{ 13 int u,v,w,next; 14 }e[2*maxn]; 15 16 void init(){ 17 ecnt = 0; 18 memset(first,-1,sizeof(first)); 19 } 20 21 void add_edges(int u,int v,int w){ 22 e[ecnt].u = u; 23 e[ecnt].v = v; 24 e[ecnt].w = w; 25 e[ecnt].next = first[u]; 26 first[u] = ecnt++; 27 } 28 29 void dfs1(int u){ 30 vis[u] = 1; 31 for(int i = first[u];~i;i=e[i].next){ 32 int v = e[i].v; 33 if(vis[v]) continue; 34 dfs1(v); 35 dp[1] += e[i].w; 36 } 37 } 38 39 void dfs2(int u){ 40 vis[u] = 1; 41 for(int i = first[u];~i;i=e[i].next){ 42 int v = e[i].v; 43 if(vis[v]) continue; 44 if(e[i].w == 0) dp[v] = dp[u] + 1; 45 else dp[v] = dp[u]-1; 46 dfs2(v); 47 } 48 } 49 50 void solve(){ 51 memset(vis,0,sizeof(vis)); 52 memset(dp,0,sizeof(dp)); 53 dfs1(1); 54 // printf("dp[1] = %d\n",dp[1]); 55 memset(vis,0,sizeof(vis)); 56 dfs2(1); 57 // for(int i = 1;i <= n;i++) printf("dp[%d] = %d\n",i,dp[i]); 58 59 int minn = (1<<30)-1; 60 for(int i = 1;i <= n;i++) minn = min(minn,dp[i]); 61 62 printf("%d\n",minn); 63 for(int i = 1;i <= n;i++) if(dp[i] == minn)printf("%d ",i); 64 printf("\n"); 65 } 66 67 int main(){ 68 while(scanf("%d",&n) != EOF){ 69 init(); 70 for(int i = 1;i <= n-1;i++){ 71 int u,v; 72 scanf("%d %d",&u,&v); 73 add_edges(u,v,0); 74 add_edges(v,u,1); 75 } 76 solve(); 77 } 78 return 0; 79 }
---------9.11
cf 577 b
http://codeforces.com/problemset/problem/577/B
补昨晚的cf
话说这一题真是坎坷--
先wa10,后来没有考虑对,状态好不容易推出来,边界又不对--
最后看了别人的代码改,才过,还不懂鸽巢原理那一块儿的证明
给出n个数(n<= 1000000),再给出m, 问能不能够从这n个数里面选择一些数出来,使得它们的和为m的倍数
第一反应就是挑战上面的dp有讲过, 可是n太大了 (可是m很小,用了鸽巢定理)
然后,自己考虑的不对的地方在于,没有想到对a[i] % m,还想着去枚举m的倍数
然后另外,就是取模之后,判断是不是能够的时候,应该是判断 dp[n][0],我想的是判断dp[n][m](真是被自己打败,明明都对m取余了的说)
然后,状态写出来之后,也一直写不对,是因为边界没有搞好----
还有 n > m的情况,所有前缀和mod m后必定有两个前缀和相等。然后中间那段的数的和mod m=0
这个还不懂证明,搞懂了再来补上吧 >_<
加油 *>_<*
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<set> 6 using namespace std; 7 8 const int maxn = 1000005; 9 int dp[1005][1005]; 10 int n,m; 11 int a[maxn]; 12 13 void solve(){ 14 if(n <= m){ 15 memset(dp,0,sizeof(dp)); 16 for(int i = 1;i <= n;i++) dp[i][a[i]] = 1; 17 for(int i = 2;i <= n;i++){ 18 for(int j = 0;j < m;j++){ 19 dp[i][j] |= dp[i-1][j]; 20 dp[i][j] |= dp[i-1][(j-a[i]+m)%m]; 21 // printf("dp[%d][%d] = %d\n",i,j,dp[i][j]); 22 } 23 } 24 if(dp[n][0]) puts("YES"); 25 else puts("NO"); 26 } 27 else{ 28 set<int> s; 29 int sum = 0; 30 for(int i = 1;i <= n;i++){ 31 sum = (sum+a[i])%m; 32 if(s.find(sum) != s.end()){ 33 puts("YES"); 34 return; 35 } 36 s.insert(sum); 37 } 38 puts("NO"); 39 } 40 } 41 42 int main(){ 43 while(scanf("%d %d",&n,&m) != EOF){ 44 memset(a,0,sizeof(a)); 45 for(int i = 1;i <= n;i++) scanf("%d",&a[i]),a[i] = a[i]%m; 46 solve(); 47 } 48 return 0; 49 }
---------9.12
其实是今天(9.13)写的--
早上YY了一下cf的那个E题,
各种排序---最后以为再改改就对了--发现少看了两个0,数量级都不对嘛-----
搜题解,说是分块---
待补---
协会纳新中--->_<感觉是我们协会的唠嗑大会
晚上做了bc
还没有补题
-------------------------------------
---------9.13
大家一起做了长春的网络赛
好残暴啊---
至少过7题才能进---
真是----------------唉,没事,加油
加油
hdu 5441
给出一个图,q个查询,查询a到b满足每条边的权值小于等于x的 点对 (a,b)
用并查集,将询问排个序,再将边排个序,依次添加合法的进去
下午比完赛,睡了一觉起来就敲
一会儿就敲完了,可是一直wa
后来---
才知道是输出记录编号那里错了,因为样例就是顺着的,怎么记录都是对的--
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 8 typedef long long LL; 9 const int maxn = 20005; 10 11 struct Edge{ 12 int u,v,d; 13 }e[10*maxn]; 14 15 int cmp1(Edge e1,Edge e2){ 16 return e1.d < e2.d; 17 } 18 19 struct node{ 20 int l,id; 21 }q[maxn]; 22 23 int cmp2(node n1,node n2){ 24 return n1.l < n2.l; 25 } 26 27 int n,m,Q; 28 29 int p[maxn],sz[maxn]; 30 LL res[maxn]; 31 32 int find(int x){return x == p[x] ? x :p[x] = find(p[x]);} 33 34 void Union(int u,int v){ 35 int x = find(u); 36 int y = find(v); 37 if(sz[x] >= sz[y]){ 38 p[y] = x; 39 sz[x] += sz[y]; 40 } 41 else{ 42 p[x] = y; 43 sz[y] += sz[x]; 44 } 45 } 46 47 int main(){ 48 int T; 49 scanf("%d",&T); 50 while(T--){ 51 memset(res,0,sizeof(res)); 52 scanf("%d %d %d",&n,&m,&Q); 53 for(int i = 1;i <= m;i++){ 54 scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].d); 55 } 56 for(int i = 1;i <= Q;i++){ 57 scanf("%d",&q[i].l); 58 q[i].id = i; 59 } 60 61 for(int i = 1;i <= n;i++) p[i] = i,sz[i] = 1; 62 sort(e+1,e+m+1,cmp1); 63 sort(q+1,q+Q+1,cmp2); 64 65 int pos = 1; 66 LL ans = 0; 67 for(int i = 1;i <= Q;i++){ 68 for(;pos <= m && e[pos].d <= q[i].l;pos++){ 69 int u = e[pos].u; 70 int v = e[pos].v; 71 int x = find(u); 72 int y = find(v); 73 if(x != y) { 74 ans += sz[x] *sz[y]*2; 75 Union(u,v); 76 } 77 } 78 res[q[i].id] = ans; 79 } 80 81 for(int i = 1;i <= Q;i++){ 82 printf("%I64d\n",res[i]); 83 } 84 } 85 return 0; 86 }