• [51Nod] 51Nod 被虐之路


    由于本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 }
    01背包 + 一维表示

    #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 }
    Miller Rabbin

     #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 }
    Hash+二分

    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 }
    Hash+补丁

    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 }
    Tarjan求强联通
     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 }
    DFS序+线段树

    #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 }
    树形DP

     #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 }
    树形DP = =
  • 相关阅读:
    NetBeans + Struts + Hibernate 入门教程
    The Perils of JavaSchools
    Java 2 EE 开发初体验
    五周年记
    MySQL Workbench 介绍
    JAVA语言学校的危险性
    娱乐无处不在 Sun工程师惊天发现:大吼可致硬盘潜伏期激增
    争什么?
    spring cloud使用zuul实现反向代理和负载均衡
    spring cloud 网管篇zuul
  • 原文地址:https://www.cnblogs.com/Chorolop/p/7716347.html
Copyright © 2020-2023  润新知