由于本Cho太过懒惰,不再更新之前已经AC以及个人认为没有很大必要写的题目;
请善用 Ctrl + F qwq
排名先后仅看做题顺序
基础题
#1.1 1085 背包问题
01背包模板
1 #include<cstdio>
2 #include<iostream>
3 using namespace std;
4
5 int n,maxx,DP[1000000],w,v;
6
7 int main(){
8 scanf("%d%d",&n,&maxx);
9
10 for(int i = 1;i <= n;i++){
11 scanf("%d%d",&w,&v);
12 for(int j = maxx;j >= w;j--)
13 DP[j] = max(DP[j],DP[j-w]+v);
14 }
15
16 cout << DP[maxx];
17
18 return 0;
19 }
#1.2 1086 背包问题 V2
多重背包 + 二进制优化
什么是二进制优化呢?当前物品有数量 c ,将其拆分成 1 2 4 8 16 ... (剩下) ,然后一个个做01背包
决策每一个数字的时候 (1,2,4...) ,选与不选,相当于该物品已有数量加不加当前数字,而我们将决策 c 的二进制表示的每一位,那么所有的 1,2,4,... 是可以组合表示出 ≤c 的所有数量的状态的
这样就优化成一层 log
1 #include<cstdio>
2 #include<iostream>
3 using namespace std;
4
5 int n,maxx,DP[1000000],w,v,c;
6
7 int main(){
8 scanf("%d%d",&n,&maxx);
9
10 for(int i = 1;i <= n;i++){
11 scanf("%d%d%d",&w,&v,&c);
12 int d = 1;
13 while(d <= c){
14 for(int j = maxx;j >= d*w;j--)
15 DP[j] = max(DP[j],DP[j-d*w]+d*v);
16 c -= d;
17 d *= 2;
18 }for(int j = maxx;c && j >= c*w;j--)
19 DP[j] = max(DP[j],DP[j-c*w]+c*v);
20 }
21
22 cout << DP[maxx];
23
24 return 0;
25 }
#1.3 1257 背包问题 V3
跟分数规划打了场遭遇战= =
数学分析目标式,二分答案
此处解题报告 [51nod] 1257 背包问题 V3
1 #include<stdio.h>
2 #include<math.h>
3 #include<iostream>
4 #include<algorithm>
5 using namespace std;
6
7 int n,k;
8 long long ansv,answ;
9
10 double eps = 0.000000001;
11
12 struct data{
13 long long w,v;
14 double vrw;
15 }arr[1000000];
16
17 bool cmp(const data &a,const data &b){ return a.vrw > b.vrw; }
18
19 bool check(long long &sumv,long long &sumw,double line){
20 for(int i = 1;i <= n;i++)
21 arr[i].vrw = 1.0*arr[i].v-line*arr[i].w;
22
23 sort(arr+1,arr+1+n,cmp);
24
25 double tmp = 0;
26 sumv = 0,sumw = 0;
27 for(int i = 1;i <= k;i++)
28 sumv += arr[i].v,
29 sumw += arr[i].w,
30 tmp += arr[i].vrw;
31
32 return tmp >= 0;
33 }
34
35 long long gcd(long long a,long long b){
36 if(a < b) swap(a,b);
37 return !b?a:gcd(b,a%b);
38 }
39
40 int main(){
41
42 scanf("%d%d",&n,&k);
43
44 for(int i = 1;i <= n;i++)
45 scanf("%lld%lld",&arr[i].w,&arr[i].v);
46
47 double L = 0,R = 1000000;
48 long long sumv,sumw;
49 while(R-L > eps){
50 // printf("%.8lf %.8lf
",L,R);
51 double mid = (L+R)/2;
52 if(check(sumv,sumw,mid)) ansv = sumv, answ = sumw, L = mid;
53 else R = mid;
54 }
55
56 long long d = gcd(ansv,answ);
57 printf("%lld/%lld",ansv/d,answ/d);
58
59 return 0;
60 }
#2.1 1136 欧拉函数
Emmmm,现在有 m 与 p 互质且 p 为质数,那么 phi( p ) = p-1 ,phi( mp ) = phi( m )*phi( p ) = phi( m )*( p-1 )
然后对于 phi( mpp ) = phi( mp )*p
Emmmm 这个我居然没法证明
我们知道如果 phi( mpp ) = phi ( mp )* ??? ,那么 ??? = phi( mpp ) / phi( mp )
而 mpp 和 mp 的质因子是一样的
所以根据公式 phi ( x ) = x*(1-.........) 我们知道对于 x 后面的部分,phi ( mpp ) 和 phi ( mp )是相同的,那么两元相除得 phi ( mpp ) / phi ( mp ) = p
1 #include<stdio.h>
2 #include<iostream>
3 using namespace std;
4
5 //int prime[100000],primesize;
6 //bool isprime[100000];
7 //void getlist(int listsize){
8 // listsize = (int)sqrt(listsize)+10;
9 // isprime[
10 //}
11
12 int phi(int &x){
13 int ans = 1;
14 for(int i = 2;i*i <= x;i++){
15 if(x%i) continue;
16 ans *= (i-1);
17 x /= i;
18 while(x%i == 0){
19 ans *= i;
20 x /= i;
21 }
22 }if(x > 1) ans *= x-1; // 这条和 i*i <= x 可以防止x为大质数导致TLE
23 return ans;
24 }
25
26 int main(){
27 int n;
28 scanf("%d",&n);
29
30 cout << phi(n);
31
32 return 0;
33 }
#3.1 1242 斐波那契数列的第N项
矩阵快速幂
1 #include<cstdio>
2 #include<iostream>
3 #define mod 1000000009
4 using namespace std;
5
6 struct MAT{
7 long long d[5][5];
8 MAT(){ d[1][1] = d[1][2] = d[2][1] = d[2][2] = 0; }
9 void Init(){
10 d[1][2] = d[2][1] = d[2][2] = 1;
11 d[1][1] = 0;
12 }
13 }I;
14
15 MAT mul(MAT A,MAT B){
16 MAT C;
17 for(int i = 1;i <= 2;i++)
18 for(int j = 1;j <= 2;j++)
19 for(int k = 1;k <= 2;k++)
20 C.d[i][j] = (C.d[i][j]+A.d[i][k]*B.d[k][j]%mod)%mod;
21 return C;
22 }
23
24 MAT ksm(MAT A,long long k){
25 MAT B = A;
26 k--;
27 while(k){
28 if(k&1) B = mul(B,A);
29 A = mul(A,A);
30 k >>= 1;
31 }return B;
32 }
33
34 int main(){
35 long long n;
36 scanf("%lld",&n);
37
38 if(n <= 2) return printf("1"),0;
39
40 MAT I;
41 I.Init();
42
43 I = ksm(I,n-1);
44
45 long long c = (I.d[1][1]+I.d[1][2])%mod;
46
47 cout << c;
48
49 return 0;
50 }
#4 1106 质数检测
Miller-Rabbin 素性测试,二次探测才是核心
1 #include<stdio.h> 2 #include<iostream> 3 #define LL long long 4 using namespace std; 5 6 int prime[8] = {2,3,5,7,11,13,17,19}; 7 8 LL ksm(LL x,LL k,LL m){ 9 if(k == 1) return x%m; 10 if(!k) return 1; 11 LL b = 1; 12 while(k){ 13 if(k&1) b = b*x%m; 14 x = x*x%m; 15 k >>= 1; 16 }return b%m; 17 } 18 19 bool TD(LL x,LL a){ 20 if(x == a) return true; 21 LL m = x-1; 22 while(m % 2 == 0) m >>= 1; 23 LL t = ksm(a,m,x); 24 while(m != x-1 && t != 1 && t != x-1) 25 t = t*t%x,m <<= 1; 26 return (m&1 || t == x-1); 27 } 28 29 bool isPrime(LL x){ 30 if(x == 2) return true; 31 if(x < 1 || x % 2 == 0) return false; 32 for(int i = 0;i < 8;i++) 33 if(!TD(x,prime[i])) return false; 34 return true; 35 } 36 37 int main(){ 38 int n; 39 scanf("%d",&n); 40 41 for(int i = 1;i <= n;i++){ 42 long long x; scanf("%lld",&x); 43 if(isPrime(x)) printf("Yes "); 44 else printf("No "); 45 } 46 47 return 0; 48 }
#5 1088 最长回文子串
Hash+二分,具体请看这里:
1 #include<stdio.h> 2 #include<iostream> 3 #include<cstring> 4 #define maxn 421357 5 #define base 21707 6 #define ULL unsigned long long 7 using namespace std; 8 9 ULL stad[maxn],anti[maxn]; 10 11 int n,ans = 1,lens; char s[maxn]; 12 13 ULL Pow(ULL x,int k){ 14 if(!k) return 1; 15 if(k == 1) return x; 16 ULL b = 1; 17 while(k){ 18 if(k&1) b = b*x; 19 x = x*x; 20 k >>= 1; 21 }return b; 22 } 23 24 ULL getcode(int L,int R){ 25 if(!L) return stad[R]; 26 else return stad[R]-stad[L-1]*Pow(base,R-L+1); 27 } 28 29 ULL getanti(int L,int R){ 30 if(R == n) return anti[L]; 31 else return anti[L]-anti[R+1]*Pow(base,R-L+1); 32 } 33 34 int find(int pos){ 35 int L = 0,R = min(lens-1-pos,pos),mid; 36 while(L < R){ 37 mid = (L+R+1)/2; 38 // printf("Checking... [%d , %d] ",pos-mid,pos+mid); 39 // ULL cntcode = (getanti(pos+1,pos+mid)*base+s[pos])*Pow(base,mid)+getcode(pos+1,pos+mid); 40 if(getcode(pos-mid,pos-1) == getanti(pos+1,pos+mid)) L = mid; 41 else R = mid-1; 42 }return L*2+1; 43 } 44 45 int exfind(int pos){ 46 if(pos == lens-1) return 0; 47 int L = 0,R = min(lens-1-pos,pos+1),mid; 48 while(L < R){ 49 mid = (L+R+1)/2; 50 // printf("Checking... [%d , %d] ",pos-mid,pos+mid); 51 // ULL cntcode = (getanti(pos+1,pos+mid)*base+s[pos])*Pow(base,mid)+getcode(pos+1,pos+mid); 52 if(getcode(pos-mid+1,pos) == getanti(pos+1,pos+mid)) L = mid; 53 else R = mid-1; 54 }return L*2; 55 } 56 57 int main(){ 58 scanf("%s",s); 59 lens = strlen(s); 60 61 ULL cntcode = 0; 62 for(int i = 0;i < lens;i++) 63 cntcode = cntcode*base+s[i], 64 stad[i] = cntcode; 65 66 cntcode = 0; 67 for(int i = lens-1;i >= 0;i--) 68 cntcode = cntcode*base+s[i], 69 anti[i] = cntcode; 70 71 for(int pos = 0;pos < lens;pos++) 72 ans = max(ans,find(pos)), 73 ans = max(ans,exfind(pos)); 74 cout << ans; 75 76 return 0; 77 }
3级算法题
#1 1267 4个数和为0
Hash+加强的check函数
1 #include<stdio.h> 2 #include<iostream> 3 #define ULL unsigned long long 4 #define maxn 1000007 5 using namespace std; 6 7 struct data{ ULL val,pos; }sum[maxn]; 8 int m,n,arr[maxn]; 9 10 struct edge{ ULL val,pos; int from; }e[maxn*4]; 11 int tot,first[maxn]; 12 13 bool noequ(ULL A,ULL B){ 14 return (A/10000 != B/10000) && (A%10000 != B%10000); 15 } 16 17 bool check(ULL val,ULL pos){ 18 int w = val%maxn; 19 for(int i = first[w];i;i = e[i].from){ 20 if(e[i].val == val && noequ(e[i].pos,pos)) return true; 21 }return false; 22 } 23 24 void insert(int pos1,int pos2,int suuum){ 25 if(pos1 > pos2) swap(pos1,pos2); 26 ULL val = (ULL)(suuum+1e9); 27 ULL kcode = pos1*10000+pos2; 28 29 if(check(val,kcode)) return; 30 31 int w = val%maxn; 32 33 tot++; e[tot].from = first[w]; 34 e[tot].val = val; e[tot].pos = kcode; 35 first[w] = tot; 36 sum[++m].val = val; 37 sum[m].pos = kcode; 38 } 39 40 int main(){ 41 scanf("%d",&n); 42 43 for(int i = 1;i <= n;i++) 44 scanf("%d",&arr[i]); 45 46 for(int i = 1;i <= n;i++) 47 for(int j = i+1;j <= n;j++) 48 insert(i,j,arr[i]+arr[j]); 49 50 // for(int i = 1;i <= m;i++) printf("%I64u %I64u ",sum[i].val,sum[i].pos); 51 // 52 // cout << "Hash:" << endl; 53 // 54 // for(int i = 1;i <= tot;i++) printf("%I64u %I64u ",e[i].val,e[i].pos); 55 56 for(int i = 1;i <= m;i++){ 57 if(check(2e9-sum[i].val,sum[i].pos)){ 58 cout << "Yes"; 59 return 0; 60 } 61 } 62 63 cout << "No"; 64 65 return 0; 66 }
4级算法题
#1 1113 矩阵快速幂
蜜汁4级,,,敲一个模板即可过。注意传参的时候推荐使用引用传参而不是直接传参。
1 #include<stdio.h>
2 #include<iostream>
3 #define LL long long
4 using namespace std;
5
6 LL mod = 1000000007;
7 int n,k;
8
9 struct mat{
10 LL d[200][200];
11 // mat(){ for(int i = 1;i <= n;i++) for(int j = 1;j <= n;j++) d[i][j] = 0; }
12 };
13
14 mat mul(mat &A,mat &B){
15 mat C;
16 for(int i = 1;i <= n;i++){
17 for(int j = 1;j <= n;j++){
18 C.d[i][j] = 0;
19 for(int k = 1;k <= n;k++)
20 C.d[i][j] = (C.d[i][j]+A.d[i][k]*B.d[k][j])%mod;
21 }
22 }return C;
23 }
24
25 mat ksm(mat &A,int k){
26 // cout<<k<<endl;
27 if(k == 1) return A;
28 // cout<<k<<endl;
29 mat B = A; k--;
30 while(k){
31 // cout<<k<<endl;
32 if(k&1) B = mul(B,A);
33 A = mul(A,A);
34 k >>= 1;
35 }return B;
36 }
37
38 int main(){
39 scanf("%d%d",&n,&k);
40
41 mat ans;
42 for(int i = 1;i <= n;i++)
43 for(int j = 1;j <= n;j++)
44 scanf("%lld",&ans.d[i][j]);
45
46 ans = ksm(ans,k);
47 // return 233;
48
49 for(int i = 1;i <= n;i++){
50 for(int j = 1;j <= n;j++)
51 printf("%lld ",ans.d[i][j]%mod);
52 cout << endl;
53 }
54
55 return 0;
56 }
#2 1051 最大子矩阵和
Emmmmmm 解法比较坑(说明我的基础已经被steam腐蚀殆尽了qwq)
首先给个优化:用前缀和储存子矩阵的和,于是枚举子矩阵的顶行和底行,那么我们就把这个矩阵在计算的时候在某种意义上压成了一行
嘿嘿嘿,然后就是最大字段和了
1 #include<stdio.h>
2 #include<iostream>
3 using namespace std;
4
5 int n,m;
6 long long cnt,ans,sum[505][505] = {0};
7
8 int main(){
9 scanf("%d%d",&m,&n);
10
11 for(int i = 1;i <= n;i++){
12 for(int j = 1;j <= m;j++){
13 scanf("%lld",&sum[i][j]);
14 sum[i][j] += sum[i-1][j];
15 }
16 }
17
18 // for(int i = 1;i <= n;i++){
19 // for(int j = 1;j <= m;j++)
20 // printf("%lld ",sum[i][j]);
21 // printf("
");
22 // }
23
24 for(int up = 0;up <= n-1;up++){
25 for(int dw = up+1;dw <= n;dw++){
26 cnt = 0;
27 for(int i = 1;i <= m;i++){
28 cnt = max(cnt+sum[dw][i]-sum[up][i],sum[dw][i]-sum[up][i]);
29 ans = max(ans,cnt);
30 // if(cnt+(sum[dw][i]-sum[up][i]) < 0){
31 // ans = max(ans,cnt); cnt = 0;
32 // }else cnt += sum[dw][i]-sum[up][i];
33 // printf("#[%d-%d]%d: %lld
",up,dw,i,cnt);
34 }
35 // ans = max(ans,cnt);
36 }
37 }printf("%lld",ans);
38
39 return 0;
40 }
#3 1287 加农炮
一道标准线段树,,, 由于最近学了一些玄学操作一开始总是想到权值线段树,然后又想到平衡树,,, = =
然而标签二分法已经揭露了一切:只需要一个普通的区间最大值定位和单点修改即可
如果左区间的最大值能够挡下这颗炮弹就朝左边找,反之右边;再反之说明这颗炮弹太高,返回一个异常值即可,然后跳过
数据不坑
1 #include<stdio.h>
2 #include<iostream>
3 #define mid (L+R)/2
4 #define lc (rt<<1)
5 #define rc (rt<<1|1)
6 #define maxn 1000000
7 using namespace std;
8
9 int n,m,connon;
10
11 struct node{
12 int maxx;
13 };
14
15 struct SegmentTree{
16 int qL,qR,val,pos;
17 node T[maxn*4];
18
19 void build(int rt,int L,int R){
20 if(L == R){ scanf("%d",&T[rt].maxx); }
21 else{
22 build(lc,L,mid); build(rc,mid+1,R);
23 T[rt].maxx = max(T[lc].maxx,T[rc].maxx);
24 }
25 }
26
27 int query(int rt,int L,int R){
28 if(L == R) return L;
29 else{
30 if(val <= T[lc].maxx) return query(lc,L,mid);
31 else if(val <= T[rc].maxx) return query(rc,mid+1,R);
32 else return 0;
33 }
34 }
35
36 void modify(int rt,int L,int R){
37 if(L == R) T[rt].maxx++;
38 else{
39 if(pos <= mid) modify(lc,L,mid);
40 else modify(rc,mid+1,R);
41 T[rt].maxx = max(T[lc].maxx,T[rc].maxx);
42 }
43 }
44
45 void print(int rt,int L,int R){
46 if(L == R) printf("%d ",T[rt].maxx);
47 else{ print(lc,L,mid); print(rc,mid+1,R); }
48 }
49
50 void Print(){ print(1,1,n); }
51
52 void Build(){ build(1,1,n); }
53
54 int Query(int heigh){ val = heigh; return query(1,1,n); }
55
56 void Modify(int Emmm){ pos = Emmm; modify(1,1,n); }
57 }A;
58
59 int main(){
60 scanf("%d%d",&n,&m);
61
62 A.Build();
63
64 for(int i = 1;i <= m;i++){
65 scanf("%d",&connon);
66 int pos = A.Query(connon);
67 if(pos <= 1) continue;
68 A.Modify(pos-1);
69 }A.Print();
70
71 return 0;
72 }
#4 1463 找朋友
这道题,跟线段树有什么关系呢??????
正解:离线 + 扫描线
注释:枚举 K 集合,将答案保存至左端点,将右端点排升序,然后计算区间 [ L,R ] 里答案的最大值(此处即可用线段树优化)
这题实在好题,思路之巧妙搞得我都想写题解了
1 #include<stdio.h>
2 #include<iostream>
3 #include<algorithm>
4 #define mid (L+R)/2
5 #define lc (rt << 1)
6 #define rc (rt<<1|1)
7 #define maxn 1000000
8 using namespace std;
9
10 int arr[maxn],brr[maxn],cnt,bos[maxn],sto[maxn],k[maxn],n,m,q;
11
12 struct node{
13 int maxx;
14 }T[maxn*4];
15
16 void build(int rt,int L,int R){
17 if(L == R) T[rt].maxx = arr[L];
18 else{
19 build(lc,L,mid); build(rc,mid+1,R);
20 T[rt].maxx = max(T[lc].maxx,T[rc].maxx);
21 }
22 }
23
24 void modify(int rt,int L,int R,int pos,int val){
25 if(L == R) T[rt].maxx = val,sto[pos] = val;
26 else{
27 if(pos > R || pos < 1) return;
28 if(pos <= mid) modify(lc,L,mid,pos,val);
29 else modify(rc,mid+1,R,pos,val);
30 T[rt].maxx = max(T[lc].maxx,T[rc].maxx);
31 }
32 }
33
34 int query(int rt,int L,int R,int qL,int qR){
35 if(qL <= L && R <= qR) return T[rt].maxx;
36 else{
37 int ans = 0;
38 if(qL <= mid) ans = max(ans,query(lc,L,mid,qL,qR));
39 if(qR > mid) ans = max(ans,query(rc,mid+1,R,qL,qR));
40 return ans;
41 }
42 }
43
44 struct ask{
45 int from,L,R,ans,ord; // first[R]
46 }e[maxn];
47 int tot,first[maxn];
48 void insert(int L,int R,int ord){
49 tot++;
50 e[tot].ord = ord,
51 e[tot].L = L,
52 e[tot].R = R,
53 e[tot].from = first[R];
54 first[R] = tot;
55 }
56
57 bool cmp(const ask &A,const ask &B){ return A.ord < B.ord; }
58
59 int main(){
60 scanf("%d%d%d",&n,&q,&m);
61
62 for(int i = 1;i <= n;i++) scanf("%d",&arr[i]);
63 for(int i = 1;i <= n;i++) scanf("%d",&brr[i]),bos[brr[i]] = i;
64 for(int i = 1;i <= m;i++) scanf("%d",&k[i]);
65
66 for(int i = 1;i <= q;i++){
67 int L,R;
68 scanf("%d%d",&L,&R);
69 insert(L,R,i);
70 }
71
72 // printf("#bos: "); for(int i = 1;i <= n;i++) printf("%d ",bos[i]); cout << endl;
73
74 for(int i = 2;i <= n;i++){
75 for(int j = 1;j <= m;j++){
76 int ppos = bos[brr[i]-k[j]]; //printf("~#%d: ppos %d i-k[j] %d
",brr[i],ppos,i-k[j]);
77 if(ppos >= 1 && ppos < i && sto[ppos] < arr[ppos]+arr[i])
78 modify(1,1,n,ppos,arr[ppos]+arr[i]);
79 ppos = bos[brr[i]+k[j]]; //printf("~#%d: ppos %d i-k[j] %d
",brr[i],ppos,i-k[j]);
80 if(ppos >= 1 && ppos < i && sto[ppos] < arr[ppos]+arr[i])
81 modify(1,1,n,ppos,arr[ppos]+arr[i]);
82 }for(int p = first[i];p;p = e[p].from){
83 e[p].ans = query(1,1,n,e[p].L,e[p].R);
84 }//printf("#%d: ",i); for(int j = 1;j <= n;j++) printf("%d ",sto[j]); cout << endl;
85 }sort(e+1,e+1+tot,cmp);
86
87 for(int i = 1;i <= tot;i++) printf("%d
",e[i].ans);
88
89 return 0;
90 }
#5 1076 2条不相交的路径
第一次写了判桥求边双...
第二次使用Tarjan求强联通的代码强行Ac...
1 #include<stdio.h> 2 #include<iostream> 3 #define maxn 2000000 4 using namespace std; 5 6 int dfn[maxn],low[maxn],TIM,s[maxn],poi,color[maxn],COL,n,m,q; 7 8 struct edge{ int from, u, v; }e[maxn]; 9 int tot,first[maxn]; void insert(int u,int v){ 10 tot++; e[tot].from = first[u]; e[tot].v = v; e[tot].u = u; first[u] = tot; 11 } 12 13 void dfs(int u,int fa){ 14 // printf("Now deep in #%d ",u); 15 dfn[u] = low[u] = ++TIM; 16 s[poi++] = u; 17 for(int i = first[u];i;i = e[i].from){ 18 int v = e[i].v; if(!dfn[v]){ 19 // printf("#%d; get in Poi B ",u); 20 dfs(v,u); low[u] = min(low[u],low[v]); 21 }else if(dfn[v] < dfn[u] && v != fa) low[u] = min(low[u],dfn[v]); 22 }//printf("#%d: get in poi A ",u); 23 24 if(low[u] == dfn[u]){ 25 // printf("#%d get the first! ",u); 26 color[u] = ++COL; 27 while(s[poi-1] != u && poi){ 28 poi--; color[s[poi]] = COL; 29 }if(poi) poi--; 30 } 31 } 32 33 int main(){ 34 scanf("%d%d",&n,&m); 35 36 for(int i = 1;i <= m;i++){ 37 int u,v; scanf("%d%d",&u,&v); 38 insert(u,v); insert(v,u); 39 }for(int i = 1;i <= n;i++) 40 if(!color[i]) dfs(i,i); 41 42 // for(int i = 1;i <= n;i++) printf("%d ",color[i]); cout << endl; 43 44 scanf("%d",&q); 45 46 for(int i = 1;i <= q;i++){ 47 int u,v; scanf("%d%d",&u,&v); 48 if(color[u] == color[v]) printf("Yes "); 49 else printf("No "); 50 } 51 52 53 54 55 return 0; 56 }
1 #include<stdio.h> 2 #include<iostream> 3 #define maxn 1000000 4 using namespace std; 5 6 int dfn[maxn],low[maxn],TIM,COL,color[maxn],n,m,q; 7 bool iscut[2*maxn],buck[maxn*2]; 8 9 struct edge{ int from,u,v,bri; }e[maxn*2]; 10 int tot,first[maxn]; void insert(int u,int v){ 11 tot++; e[tot].bri = 0; e[tot].u = u; e[tot].from = first[u]; e[tot].v = v; first[u] = tot; 12 } 13 14 void dfs(int u,int fa){ // To tag the bri 15 dfn[u] = low[u] = ++TIM; 16 int child = 0; 17 for(int i = first[u];i;i = e[i].from){ 18 int v = e[i].v; //if(v == fa) continue; 19 if(v != fa) child++; 20 if(!dfn[v]){ 21 dfs(v,u); 22 low[u] = min(low[u],low[v]); 23 if(low[v] >= dfn[u]) iscut[u] = true; 24 }else if(dfn[v] < dfn[u] && v != fa) low[u] = min(low[u],dfn[v]); 25 }if(fa == u && child > 1) iscut[u] = false; 26 // printf("#%d: child %d iscut %d ",u,child,iscut[u]); 27 } 28 29 void tagg(){ 30 for(int i = 1;i <= tot;i++) 31 if(iscut[e[i].u] && iscut[e[i].v]) 32 e[i].bri = 1, buck[i] = true; 33 } 34 35 void dfs1(int u,int fa){ 36 color[u] = COL; 37 for(int i = first[u];i;i = e[i].from){ 38 if(e[i].v == fa || buck[i] || color[e[i].v]) continue; 39 dfs1(e[i].v,u); 40 } 41 } 42 43 int main(){ 44 // freopen("16.txt","r",stdin); 45 // freopen("16.out","w",stdout); 46 47 scanf("%d%d",&n,&m); 48 49 for(int i = 1;i <= m;i++){ 50 int u,v; scanf("%d%d",&u,&v); 51 insert(u,v); insert(v,u); 52 }for(int i=1;i<=n;i++)if(!dfn[i]) 53 dfs(i,i); for(int i = 1;i <= n;i++) 54 if(!e[first[i]].from) iscut[i] = true; 55 // for(int i = 1;i <= n;i++) printf("%d ",iscut[i]); cout << endl; 56 tagg(); 57 58 // for(int i = 1;i <= tot;i++) printf("#%d:%d->%d $%d$ ",i,e[i].u,e[i].v,buck[i]); 59 // for(int i = 1;i <= n;i++) printf("%d ",color[i]); cout << endl; 60 61 for(int i = 1;i <= n;i++) 62 if(!color[i]){ ++COL; dfs1(i,i); } 63 64 scanf("%d",&q); 65 66 for(int i = 1;i <= q;i++){ 67 int u,v; scanf("%d%d",&u,&v); 68 if(color[u] == color[v]) printf("Yes "); 69 else printf("No "); 70 } 71 72 return 0; 73 }
5级算法题
#1 1494 选举拉票
Orz 这道题,当真是思考题
具体请看这里:[BZOJ] 1494 选举拉票 #算法设计策略
1 #include<stdio.h>
2 #include<queue>
3 #include<algorithm>
4 #include<iostream>
5 #define mid (L+R)/2
6 #define lc (rt<<1)
7 #define rc (rt<<1|1)
8 #define maxn 200000
9 using namespace std;
10
11 long long n,list[maxn],qwq;
12 bool vis[maxn];
13
14 struct nodd{
15 long long num,sum;
16 }T[maxn*4];
17
18 void modify(long long rt,long long L,long long R,long long pos,long long val){
19 if(pos < L || pos > R) return;
20 if(L == R) T[rt].num += val,T[rt].sum += val*pos;
21 else{
22 /*if(pos <= mid)*/ modify(lc,L,mid,pos,val);
23 /*else*/ modify(rc,mid+1,R,pos,val);
24 T[rt].num = T[lc].num+T[rc].num;
25 T[rt].sum = T[lc].sum+T[rc].sum;
26 }
27 }
28
29 long long query(long long rt,long long L,long long R,long long pos){
30 if(pos <= 0) return 0;
31 if(pos > T[rt].num) return 2e9;
32 if(L == R) return L*pos;//T[rt].sum;
33 else if(pos <= T[lc].num) return query(lc,L,mid,pos);
34 else return T[lc].sum + query(rc,mid+1,R,pos-T[lc].num);
35 }
36
37 priority_queue<long long,vector<long long> ,greater<long long> > heap[maxn];
38
39 bool cmp1(long long A,long long B){ return heap[A].size() > heap[B].size(); }
40
41 int main(){
42 scanf("%lld",&n);
43
44 for(int i = 1;i <= n;i++){
45 long long x,y;
46 scanf("%lld%lld",&x,&y);
47 heap[x].push(y);
48 if(x&&!vis[x]) list[++qwq] = x,vis[x] = true;
49 if(x) modify(1,0,20000,y,1);
50 }
51
52 sort(list+1,list+1+qwq,cmp1);
53 // cout << "list";
54 // for(int i = 1;i <= qwq;i++) printf("%d ",list[i]); cout << endl;
55 long long s = heap[0].size(),num = 0,sum = 0,ans = 2e9;
56
57 for(int i = n;i >= max(1LL,s);i--){
58 for(int j = 1;j <= qwq;j++){
59 if(heap[list[j]].size() < i) break;
60 while(heap[list[j]].size() >= i){
61 sum += heap[list[j]].top();
62 modify(1,0,20000,heap[list[j]].top(),-1);
63 heap[list[j]].pop();
64 num++;
65 }
66 }ans = min(ans,sum+query(1,0,20000,i-(num+s)));
67 // printf("#%d: ans %d
",i,ans);
68 }
69
70 printf("%lld",ans);
71
72 return 0;
73 }
#2 1199 Money out of Thin Air
使用线段树维护树的欧拉序
1 #include<stdio.h> 2 #include<iostream> 3 #define mid (L+R)/2 4 #define lc (rt<<1) 5 #define rc (rt<<1|1) 6 #define maxn 1000000 7 #define LL long long 8 using namespace std; 9 10 int dfn[maxn],dfl[maxn],TIM,sz[maxn],fa[maxn],n,m; 11 LL vval[maxn],arr[maxn],ans[maxn]; 12 13 struct edge{ 14 int from,v; 15 }e[maxn]; int tot,first[maxn]; 16 void insert(int u,int v){ tot++; e[tot].from = first[u]; e[tot].v = v; first[u] = tot; } 17 18 void dfs(int u){ 19 dfn[u] = ++TIM; 20 arr[TIM] = vval[u]; 21 sz[u] = 1; 22 for(int i = first[u];i;i = e[i].from){ 23 int v = e[i].v; 24 dfs(v); 25 sz[u] += sz[v]; 26 }dfl[u] = TIM; 27 } 28 29 struct node{ 30 LL sum,lazy; 31 }T[maxn*4]; 32 33 void pushdown(int rt,int L,int R){ 34 if(!T[rt].lazy) return; 35 T[lc].lazy += T[rt].lazy; 36 T[rc].lazy += T[rt].lazy; 37 T[lc].sum += T[rt].lazy*(mid-L+1); 38 T[rc].sum += T[rt].lazy*(R-mid); 39 T[rt].lazy = 0; 40 } 41 42 void build(int rt,int L,int R){ // 1,1,TIM 43 if(L == R) T[rt].sum = arr[L]; 44 else{ 45 build(lc,L,mid); build(rc,mid+1,R); 46 T[rt].sum = T[lc].sum+T[rc].sum; 47 } 48 } 49 50 LL query(int rt,int L,int R,int qL,int qR){ 51 pushdown(rt,L,R); 52 if(qL <= L && R <= qR) return T[rt].sum; 53 else{ 54 LL ret = 0; 55 if(qL <= mid) ret += query(lc,L,mid,qL,qR); 56 if(qR > mid) ret += query(rc,mid+1,R,qL,qR); 57 return ret; 58 } 59 } 60 61 void modify(int rt,int L,int R,int qL,int qR,LL val){ 62 pushdown(rt,L,R); 63 if(qL <= L && R <= qR){ 64 T[rt].sum += val*(R-L+1); 65 T[rt].lazy += val; 66 }else{ 67 if(qL <= mid) modify(lc,L,mid,qL,qR,val); 68 if(qR > mid) modify(rc,mid+1,R,qL,qR,val); 69 T[rt].sum = T[lc].sum + T[rc].sum; 70 } 71 } 72 73 void print(int rt,int L,int R){ 74 pushdown(rt,L,R); 75 if(L == R) ans[L] = T[rt].sum; 76 else{ 77 print(lc,L,mid); 78 print(rc,mid+1,R); 79 } 80 } 81 82 void final(){ 83 for(int i = 1;i <= n;i++) printf("%lld ",ans[dfn[i]]); 84 } 85 86 int main(){ 87 // freopen("1.in","r",stdin); 88 89 scanf("%d%d",&n,&m); 90 91 for(int i = 2;i <= n;i++){ 92 scanf("%d%lld",&fa[i],&vval[i]); 93 insert(fa[i]+1,i); 94 // insert(fa[i],i); 95 } 96 97 dfs(1); 98 build(1,1,TIM); 99 100 for(int i = 1;i <= m;i++){ 101 char ctr; int x; LL z; double y; 102 cin >> ctr; scanf("%d%lf%lld",&x,&y,&z); 103 104 x++; 105 if(ctr == 'A'){ 106 LL sum = query(1,1,TIM,dfn[x],dfl[x]); 107 if(1.0*sum/(dfl[x]-dfn[x]+1) < y) modify(1,1,TIM,dfn[x],dfl[x],z); 108 }else if(1.0*query(1,1,TIM,dfn[x],dfn[x]) < y) modify(1,1,TIM,dfn[x],dfn[x],z); 109 // cout << "BBB" << endl; 110 } 111 112 print(1,1,TIM); 113 final(); 114 115 return 0; 116 }
#3 1378 夹克老爷的愤怒
树形DP
具体请看这里:[51nod] 1378 夹克老爷的愤怒 #树形DP
1 #include<stdio.h> 2 #include<iostream> 3 #define maxn 1000000 4 using namespace std; 5 6 int DP[maxn][5],buoy[maxn],anch[maxn],depth[maxn],sz[maxn],n,k; 7 8 struct edge{ 9 int from,v; 10 }e[maxn*2]; int tot,first[maxn]; 11 void insert(int u,int v){ tot++; e[tot].from = first[u]; e[tot].v = v; first[u] = tot; } 12 13 void dfs(int u,int pre){ 14 int sum = 0; sz[u] = 1; 15 DP[u][0] = DP[u][1] = 0; buoy[u] = 1e9; anch[u] = -1e9; 16 for(int i = first[u];i;i = e[i].from){ 17 int v = e[i].v; if(v == pre) continue; 18 depth[v] = depth[u]+1; 19 dfs(v,u); 20 sz[u] += sz[v]; 21 buoy[u] = min(buoy[u],buoy[v]); 22 anch[u] = max(anch[u],anch[v]); 23 sum += DP[v][0]; 24 } 25 26 if(sz[u] == 1){ 27 DP[u][1] = 1; 28 DP[u][0] = 0; 29 if(!k) DP[u][0] = 1; 30 buoy[u] = anch[u] = depth[u]; 31 return; 32 } 33 34 // printf("#%d: buoy%d anch%d ",u,buoy[u],anch[u]); 35 if(anch[u]-depth[u] >= k){ // Must set 36 // printf("#%d: Poi A ",u); 37 DP[u][0] = DP[u][1] = sum+1; 38 buoy[u] = depth[u]-k; 39 anch[u] = buoy[u]-1; 40 }else if(2*depth[u]-buoy[u] < anch[u]){ // Can choose 41 // printf("#%d: Poi B ",u); 42 DP[u][0] = sum; 43 DP[u][1] = sum+1; 44 }else{ // Needn't 45 // printf("#%d: Poi C ",u); 46 DP[u][0] = DP[u][1] = sum; 47 anch[u] = buoy[u]-1; 48 } 49 } 50 51 int main(){ 52 scanf("%d%d",&n,&k); 53 54 for(int i = 1;i < n;i++){ 55 int u,v; scanf("%d%d",&u,&v); 56 u++,v++; insert(u,v); insert(v,u); 57 }depth[1] = 1; 58 59 dfs(1,1); 60 61 printf("%d ",DP[1][1]); 62 63 // for(int i = 1;i <= n;i++){ 64 // printf("#%d: 0:%d 1:%d buoy:%d anch:%d ",i,DP[i][0],DP[i][1],buoy[i],anch[i]); 65 // } 66 67 return 0; 68 }
#4 1424 零树
树形DP,这道题是看着题解过的因此并不想写博客
DP[ u ][ 1/0 ]:1和0分别表示到这个点需要增加和减少的操作次数
显然,直接一次操作最值即可
= =
1 #include<stdio.h> 2 #include<iostream> 3 #define maxn 1000000 4 #define heng(x) (x<0?(-x):x) 5 using namespace std; 6 7 long long DP[maxn][5],val[maxn],n; 8 9 struct edge{ 10 int from,v; 11 }e[maxn*2]; int first[maxn],tot; 12 void insert(int u,int v){ tot++; e[tot].from = first[u]; e[tot].v = v; first[u] = tot; } 13 14 void dfs(int u,int pre){ 15 DP[u][0] = DP[u][1] = 0; 16 // if(val[u] < 0) DP[u][0] = -val[u],DP[u][1] = 0; 17 // else DP[u][0] = 0,DP[u][1] = val[u]; 18 19 for(int i = first[u];i;i = e[i].from){ 20 int v = e[i].v; if(v == pre) continue; 21 dfs(v,u); 22 DP[u][0] = max(DP[u][0],DP[v][0]); 23 DP[u][1] = max(DP[u][1],DP[v][1]); 24 }int del = DP[u][1]-DP[u][0]+val[u]; 25 DP[u][del<0] += heng(del); 26 } 27 28 int main(){ 29 scanf("%lld",&n); 30 for(int i = 1;i < n;i++){ 31 int u,v; scanf("%d%d",&u,&v); 32 insert(u,v); insert(v,u); 33 }for(int i = 1;i <= n;i++) scanf("%lld",&val[i]); 34 35 dfs(1,1); 36 37 38 printf("%lld",DP[1][0]+DP[1][1]); 39 40 return 0; 41 }