zoukankan      html  css  js  c++  java
  • 那些年没有AC的水题...

    1 HDU 5492(dp

    题目:一个数字矩阵,要求找到一条路径使得经过的数字的方差最小.

    思路:稍微把式子变换一下,状态是走到当前格子和为k时最小平方和.

    /*
    * @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-6)
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000000)
    #define FINF (1e3)
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxsum=1900;
    const int maxn=40;
    int T,n,m;
    int grid[maxn][maxn];
    int dp[maxn][maxn][maxsum];
    int h[maxn][maxn];
    int pos[maxn][maxn][maxsum];
    int inf;
    int cas=0;
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("test.in","r",stdin);
        //freopen("test.out","w",stdout);
        memset(dp,0x3f,sizeof dp);
        inf=dp[0][0][0];
        cin>>T;
        while(T--){
            cin>>n>>m;
            for(int i=0;i<n;i++){
                for(int j=0;j<m;j++){
                    scanf("%d",&grid[i][j]);
                }
            }
            dp[0][0][grid[0][0]]=sq(grid[0][0]);
            pos[0][0][0]=grid[0][0];
            h[0][0]=1;
            int ans=inf;
            for(int i=0;i<n;i++){
                for(int j=0;j<m;j++){
                    for(int k=0;k<h[i][j];k++){
                        int v=pos[i][j][k];
                        if(dp[i+1][j][v+grid[i+1][j]]==inf){
                            pos[i+1][j][h[i+1][j]++]=v+grid[i+1][j];
                            dp[i+1][j][v+grid[i+1][j]]=dp[i][j][v]+sq(grid[i+1][j]);
                        }else{
                            dp[i+1][j][v+grid[i+1][j]]=
                                min(dp[i][j][v]+sq(grid[i+1][j]),
                                    dp[i+1][j][v+grid[i+1][j]]);
                        }
                        if(dp[i][j+1][v+grid[i][j+1]]==inf){
                            pos[i][j+1][h[i][j+1]++]=v+grid[i][j+1];
                            dp[i][j+1][v+grid[i][j+1]]=dp[i][j][v]+sq(grid[i][j+1]);
                        }else{
                            dp[i][j+1][v+grid[i][j+1]]=
                                min(dp[i][j][v]+sq(grid[i][j+1]),
                                    dp[i][j+1][v+grid[i][j+1]]);
                        }
                        if(i==n-1&&j==m-1){
                            ans=min(ans,dp[i][j][v]*(n+m-1)-v*v);
                        }
                        dp[i][j][v]=inf;
                    }
                    h[i][j]=0;
                }
            }
            for(int i=0;i<=max(n,m);i++){
                for(int j=0;j<h[i][m];j++){
                    int v=pos[i][m][j];
                    dp[i][m][v]=inf;
                }
                h[i][m]=0;
                for(int j=0;j<h[n][i];j++){
                    int v=pos[n][i][j];
                    dp[n][i][v]=inf;
                }
                h[n][i]=0;
            }
            printf("Case #%d: %d
    ",++cas,ans);
        }
        return 0;
    }
    View Code

     2 CF 559C

    题目:一个棋盘上有若干个格子不能经过,求从左上角走到右下角的方案数.

    思路:dp[i]表示走到第i个不能走的点的走法种数,那么这个答案就等于总的走法减去禁止的走法,禁止的走法可以枚举经过的第一个禁止点的位置得到.

    /*
    * @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-6)
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000000)
    #define FINF (1e3)
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    
    const ll mod=1e9+7;
    const int maxv=2e5+600;
    ll inv[maxv];
    ll fac[maxv];
    ll qpow(ll a,ll p,ll m){
        ll ans=1;
        while(p){
            if(p&1) ans=(ans*a)%m;
            p>>=1;
            a=(a*a)%m;
        }
        return ans;
    }
    void init(){
        fac[0]=1;
        for(ll i=1;i<maxv;i++){
            fac[i]=fac[i-1]*i%mod;
        }
        inv[0]=1;
        for(ll i=1;i<maxv;i++){
            inv[i]=inv[i-1]*qpow(i,mod-2,mod)%mod;
        }
    }
    ll getC(int n,int r){
        return fac[n]*inv[n-r]%mod*inv[r]%mod;
    }
    const int maxn=2005;
    struct Point{
        int x,y;
        bool operator < (const Point &C)const {
            if(x!=C.x) return x<C.x;
            else return y<C.y;
        }
    }a[maxn];
    ll h,w,n;
    ll dp[maxn];
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        init();
        cin>>h>>w>>n;
        for(int i=1;i<=n;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            a[i].x=x,a[i].y=y;
        }
        a[n+1]=(Point){h,w};
        sort(a+1,a+n+1);
        a[0]=(Point){1,1};
        for(int i=1;i<=n+1;i++){
            ll tmp=0;
            dp[i]=getC(a[i].x-a[0].x+a[i].y-a[0].y,a[i].x-a[0].x);
            for(int j=0;j<i;j++){
                if(a[j].y<=a[i].y)
                    tmp=(tmp+dp[j]*getC(a[i].x-a[j].x+a[i].y-a[j].y,a[i].x-a[j].x)%mod)%mod;
            }
            tmp=mod-tmp;
            dp[i]=(dp[i]+tmp)%mod;
        }
        cout<<dp[n+1]<<endl;
        return 0;
    }
    View Code

     3 HDU 5469

    题目:一棵树的每个节点有一个字母,问是否有一条路径组成了指定的字符串.

    思路:直接hash+分治,写了差不多一整天....写到都感觉"啊..分治就这么点东西怎么就是不对呢...",然后看了会动漫调整了一下心态,出了个出错的数据才把这题过掉.....这种时候要出一些看起来不会错但是比较复杂的数据,一定不能偷懒...

    /*
    * @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-6)
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000000)
    #define FINF (1e3)
    #define mem(x) memset((x),0,sizeof (x));
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const ll mod=1e9+7;
    const ll H=3457;
    const int maxn=1e4+3000;
    int T;
    int n;
    char c[maxn],s[maxn];
    vector<int> G[maxn];
    ll hp[maxn];
    bool used[maxn];
    int cnt;
    int ch=0;
    void count(int v,int f=-1){
        cnt++;
        for(int i=0;i<G[v].size();i++){
            int u=G[v][i];
            if(u==f||used[u]) continue;
            count(u,v);
        }
    }
    int snum[maxn];
    int center,mind;
    void getCenter(int v,int f=-1){
        snum[v]=0;
        int maxs=0;
        for(int i=0;i<G[v].size();i++){
            int u=G[v][i];
            if(u==f||used[u]) continue;
            getCenter(u,v);
            snum[v]+=snum[u]+1;
            maxs=max(maxs,snum[u]+1);
        }
        if(max(maxs,cnt-snum[v]-1)<mind){
            mind=max(maxs,cnt-snum[v]-1);
            center=v;
        }
    }
    
    int ls;
    ll shash1[maxn],shash2[maxn];
    int ff[maxn],aa[maxn];
    int getfore(int len){return ((shash2[1]-(ll)shash2[len+1]*hp[len])%mod+mod+mod)%mod;}
    int getafter(int len){return ((shash1[ls]-(ll)shash1[ls-len]*hp[len])%mod+mod+mod)%mod;}
    int findfore[maxn],findafter[maxn];
    int branch;
    
    void calhash(int v,ll hash,int d,int f){
        ll val=(hash*H+c[v-1])%mod;
        if(val==ff[d+1]){
            if(!findfore[d+1]) findfore[d+1]=branch;
            else if(findfore[d+1]!=branch) findfore[d+1]=-1;
        }
        if(val==aa[d+1]){
            if(!findafter[d+1])findafter[d+1]=branch;
            else if(findafter[d+1]!=branch)findafter[d+1]=-1;
        }
        for(int i=0;i<G[v].size();i++){
            int u=G[v][i];
            if(u==f||used[u]) continue;
            calhash(u,val,d+1,v);
        }
    }
    bool solve(int v){
        used[v]=1;
        branch=1;
        ch=0;
        mem(findfore);mem(findafter);
        findfore[0]=findafter[0]=-1;
        for(int i=0;i<G[v].size();i++){
            int u=G[v][i];
            if(used[u]) continue;
            calhash(u,0,0,v);
            branch++;
        }
        for(int i=0;i<ls;i++){
            if(c[v-1]==s[i]){
                if(!findfore[i]||!findafter[ls-i-1])continue;
                if(findfore[i]>0&&findafter[ls-i-1]>0&&findfore[i]==findafter[ls-i-1])continue;
                return 1;
            }
        }
        for(int i=0;i<G[v].size();i++){
            int u=G[v][i];
            if(used[u]) continue;
            cnt=0;
            count(u);
            if(cnt<ls) continue;
            mind=1e9;
            getCenter(u);
            if(solve(center))return 1;
        }
        return 0;
    }
    int cas=0;
    void init(){
        for(int i=0;i<=n;i++){
            G[i].clear();
            used[i]=0;
        }
    }
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        hp[0]=1;
        for(int i=1;i<maxn;i++)
            hp[i]=hp[i-1]*H%mod;
        cin>>T;
        while(T--){
            cin>>n;
            init();
            for(int i=0;i<n-1;i++){
                int a,b;
                scanf("%d%d",&a,&b);
                G[a].pb(b);
                G[b].pb(a);
            }
            scanf("%s%s",c,s);
            ls=strlen(s);
            for(int i=1;i<=ls;i++) shash1[i]=(shash1[i-1]*H%mod+s[i-1])%mod;
            shash2[ls+1]=0;
            for(int i=ls;i>=1;i--){shash2[i]=(shash2[i+1]*H%mod+s[i-1])%mod;}
            for(int i=0;i<=ls;i++) ff[i]=getfore(i),aa[i]=getafter(i);
            cnt=0;
            mind=1e9;
            count(1);
            getCenter(1);
            if(solve(center))printf("Case #%d: Find
    ",++cas);
            else printf("Case #%d: Impossible
    ",++cas);
        }
        return 0;
    }
    View Code

     4 HDU 5468

    题目:给出一棵树,求每个节点的子树中和这个节点的值互质的数有多少个.

    思路:由于只有1e5的数据,所以可以记录每个素数分解的倍数的个数,然后每个子树处理完之后和之前的值减一下就是当前子树中的值.然后容斥原理搞一搞就好了.

    /*
    * @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-6)
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000000)
    #define FINF (1e3)
    #define clr(x) memset((x),0,sizeof (x));
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxn=1e5+400;
    int n;
    int cnt[maxn],val[maxn],ans[maxn];
    vector<int> G[maxn],fac[maxn];
    int mp[maxn];
    void dfs(int v,int f=-1){
        int pre[80];
        clr(pre);
        int sz=fac[val[v]].size();
        for(int mask=0;mask<(1<<sz);mask++){
            int tmp=1;
            for(int j=0;j<sz;j++) if((1<<j)&mask) tmp*=fac[val[v]][j];
            pre[mask]=cnt[tmp];
            cnt[tmp]++;
        }
        for(int i=0;i<G[v].size();i++){
            int u=G[v][i];
            if(u==f) continue;
            dfs(u,v);
        }
        for(int mask=0;mask<(1<<sz);mask++){
            int tmp=1,f=-1;
            for(int j=0;j<sz;j++)if((1<<j)&mask)
                {tmp*=fac[val[v]][j];f*=-1;}
            ans[v]-=f*(cnt[tmp]-pre[mask]);
        }
    }
    void init_cal(){
        for(int i=2;i<maxn;i++)if(!mp[i])
            for(int j=i;j<maxn;j+=i){fac[j].pb(i);mp[j]=1;}
    }
    void init(){for(int i=0;i<=n;i++) G[i].clear();clr(cnt);clr(ans);}
    int cas=0;
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        init_cal();
        while(cin>>n){
            init();
            for(int i=0;i<n-1;i++){
                int a,b;
                scanf("%d%d",&a,&b);
                G[a].pb(b);
                G[b].pb(a);
            }
            for(int i=1;i<=n;i++) scanf("%d",&val[i]);
            dfs(1);
            printf("Case #%d:",++cas);
            for(int i=1;i<=n;i++) printf(" %d",ans[i]);
            puts("");
        }    
        return 0;
    }
    View Code

    5  CF 582B

    题目:一个数列复制t份首尾相接,求这个数列的最长递增子序列的长度.

    思路:这题的一种做法是求前后n段的结果,中间的值都取相同的(只算一段直觉上也是对的,但是显然n段不可能有任何问题,所以不要作死)..另一种做法是矩阵快速幂..但是矩阵快速幂本质上都是dp,所以从dp的角度来考虑.状态dp[i][j]为以大于等于i的数字开头,(当前串的最后一段)以第j个数字结尾的最长序列长度,然后做快速幂.这个状态很巧妙,考虑到a的取值范围在300以内,可以把值作为状态,但是实际的n值更小,这样的状态表示更有效率(如果状态开到300可能会t).最后,对于这种多段问题,矩阵解法表示的一定是在某种约束条件下,最后一段的状态(这样才能dp),由于对这一点理解不清所以看了挺长时间..

    /*
    * @author:  Cwind
    */
    #include <bits/stdc++.h>
    #define pb push_back
    #define se second
    #define fs first
    #define sq(x) (x)*(x)
    #define eps (5e-12)
    #define LB lower_bound
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000000)
    #define bk back()
    #define PB pop_back
    #define clr(x) memset((x),0,sizeof (x));
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> P;
    
    const int maxn=105;
    int val[maxn];
    int n,t;
    int tmp[maxn][maxn];
    struct Matirx{
        int a[maxn][maxn];
        Matirx(){
            clr(a);
        }
        void multi(const Matirx &C){
            clr(tmp);
            for(int i=0;i<n;i++){
                for(int j=0;j<n;j++){
                    tmp[i][j]=-INF;
                    for(int k=0;k<n;k++){
                        tmp[i][j]=max(tmp[i][j],a[i][k]+C.a[k][j]);
                    }
                }
            }
            for(int i=0;i<n;i++)
                for(int j=0;j<n;j++)
                    a[i][j]=tmp[i][j];
        }
    };
    Matirx qpow(Matirx a,int p){
        Matirx ans,tmp;
        while(p){
            if(p&1) ans.multi(a);
            p>>=1;
            tmp=a;
            a.multi(tmp);
        }
        return ans;
    }
    int mat[maxn][maxn];
    int main(){
        //freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("test.in","r",stdin);
        //freopen("test.out","w",stdout);
        cin>>n>>t;
        for(int i=0;i<n;i++){
            scanf("%d",&val[i]);
        }
        for(int s=0;s<n;s++){
            for(int i=0;i<n;i++){
                if(val[i]<val[s]){
                    mat[s][i]=-INF;
                }else{
                    mat[s][i]=1;
                    for(int j=0;j<i;j++){
                        if(val[j]<=val[i])
                            mat[s][i]=max(mat[s][i],mat[s][j]+1);
                    }
                }
            }
        }
        Matirx A;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                A.a[i][j]=mat[i][j];
            }
        }
        Matirx ans=qpow(A,t);
        int aa=0;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                aa=max(aa,ans.a[i][j]);
            }
        }
        cout<<aa<<endl;
        return 0;    
    }
    View Code

     6 CF 584E

    题目:交换两个数字的花费为这两个数字的位置差,求把一个排列变成另一个排列的最小花费。

    思路:先把排列转换成1~n的排列,要吧这个序列转换成顺序排列。做法是从大到小,把没到位置的最大数往后移,并保证不产生多余的花销(不会把一个较大的数移动到它位置的左边)。通过指针移动操作一个数的复杂度是O(n)。这种移动是必然存在满足条件的操作的,因为位置在x之后的数字有n-x个,并且大于x的数字有n-x个,但是由于n在位置x,所以由容斥可知必然存在要求的数字。

    /*
    * @author:  Cwind
    */
    #include <bits/stdc++.h>
    #define pb push_back
    #define se second
    #define fs first
    #define sq(x) (x)*(x)
    #define eps (5e-12)
    #define LB lower_bound
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000000)
    #define bk back()
    #define PB pop_back
    #define clr(x) memset((x),0,sizeof (x));
    using namespace std;
    typedef int ll;
    typedef pair<ll,ll> P;
    
    const int maxn=2005;
    int n;
    int a[maxn],b[maxn];
    vector<P> op;
    int main(){
    //    freopen("/home/slyfc/CppFiles/in","r",stdin);
        cin>>n;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        for(int i=1;i<=n;i++){
            int x;
            scanf("%d",&x);
            b[x]=i;
        }
        for(int i=1;i<=n;i++){
            a[i]=b[a[i]];
        }
        ll cost=0;
        for(int i=n;i>=1;i--){
            int pos;
            for(int j=1;j<=n;j++){
                if(a[j]==i){
                    pos=j;
                    break;
                }
            }
            while(pos<i){
                int t=pos+1;
                while(a[t]>pos) t++;
                cost+=abs(pos-t);
                swap(a[pos],a[t]);
                op.pb(P(pos,t));
                pos=t;
            }
        }
        cout<<cost<<endl;
        cout<<op.size()<<endl;
        for(int i=0;i<op.size();i++){
            printf("%d %d
    ",op[i].fs,op[i].se);
        }
        return 0;    
    }
    View Code

     7 CF 587B

    题目:给出由a串重复若干次形成的数列b,求数列b中的长度小于等于k的不降子序列的数量。

    思路:由于限定了相邻两项不在同一个a里,所以这题就很简单了(然而比赛的时候脑残居然写挂了。。。。。),统计的时候由于顺序关系,可以用树状数组求和。当然dp的时候完全可以先把a排序,然后求前缀和。

    /*
    * @author:  Cwind
    */
    #include <bits/stdc++.h>
    #define pb push_back
    #define se second
    #define fs first
    #define sq(x) (x)*(x)
    #define eps (5e-12)
    #define LB lower_bound
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000000)
    #define bk back()
    #define PB pop_back
    #define clr(x) memset((x),0,sizeof (x));
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> P;
    
    const ll mod=1e9+7;
    const int maxn=1e6+3000;
    ll n,l,k;
    int h;
    int lim;
    struct BIT{
        ll a[maxn];
        ll sum(int p){
            ll ans=0;
            while(p>0){
                ans=(ans+a[p])%mod;
                p-=p&-p;
            }
            return ans;
        }
        void add(int p,ll x){
            while(p<lim){
                a[p]=(a[p]+x)%mod;
                p+=p&-p;
            }
        }
        void clear(){
            for(int i=0;i<=lim;i++){
                a[i]=0;
            }
        }
    }B[2];
    int dd[maxn];
    int a[maxn];
    int main(){
        freopen("/home/slyfc/CppFiles/in","r",stdin);
        cin>>n>>l>>k;
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
            dd[i]=a[i];
        }
        sort(dd,dd+n);
        h=unique(dd,dd+n)-dd;
        lim=h+300;
        ll ans=l%mod;
        if(l<=n){
            cout<<l%mod<<endl;
            return 0;
        }
        for(int i=0;i<n;i++){
            a[i]=lower_bound(dd,dd+h,a[i])-dd+1;
        }
        bool f=0;
        for(int i=0;i<n;i++){
            B[f].add(a[i],1);
        }
        ll xx=min(k,l/n);
        for(int len=2;len<=xx;len++){
            f^=1;
            B[f].clear();
            for(int i=0;i<n;i++){
                B[f].add(a[i],B[f^1].sum(a[i]));
                if(l%n!=0&&i+1==l%n) ans=(ans+B[f].sum(lim))%mod;
            }
            ans=(ans+B[f].sum(lim)*(l/n%mod-len+1+3*mod)%mod)%mod;
        }
        if(l%n!=0&&k>xx&&xx<=l/n+1){
            f^=1;
            B[f].clear();
            for(int i=0;i<l%n;i++){
                B[f].add(a[i],B[f^1].sum(a[i]));
            }
            ans=(ans+B[f].sum(lim))%mod;
        }
        cout<<ans<<endl;
        return 0;    
    }
    View Code

     8 CF 587C

    题目:一棵树的每个节点有若干值,询问某两点之间路径上的最小的a个值。

    思路:裸倍增lca。

    /*
    * @author:  Cwind
    */
    #include <bits/stdc++.h>
    #define pb push_back
    #define se second
    #define fs first
    #define sq(x) (x)*(x)
    #define eps (5e-12)
    #define LB lower_bound
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF (1000000000)
    #define bk back()
    #define PB pop_back
    #define clr(x) memset((x),0,sizeof (x));
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> P;
    
    
    void print(vector<int> &a){
        for(int i=0;i<a.size();i++){
            printf("%d ",a[i]);
        }
        puts("");
    }
    const int maxn=1e5+300;
    int n,m,q;
    vector<int> G[maxn];
    vector<int> ls[maxn][18];
    int pa[maxn][18];
    int dep[maxn];
    void dfs(int v,int f=0,int d=0){
        pa[v][0]=f;dep[v]=d;
        for(int i=0;i<G[v].size();i++){
            int u=G[v][i];
            if(u==f) continue;
            dfs(u,v,d+1);
        }
    }
    int mergelim=10;
    void merge(vector<int> &a,vector<int> &b,vector<int> &c){
        int h1=0,h2=0;
        while(h1<a.size()&&h2<b.size()&&c.size()<mergelim){
            if(a[h1]<b[h2]){
                if(!c.size()||c.bk!=a[h1]){
                    c.pb(a[h1]);
                }
                h1++;
            }else{
                if(!c.size()||c.bk!=b[h2]){
                    c.pb(b[h2]);
                }
                h2++;
            }
        }
        while(h1<a.size()&&c.size()<mergelim){
            if(!c.size()||c.bk!=a[h1]){
                c.pb(a[h1]);
            }
            h1++;
        }
        while(h2<b.size()&&c.size()<mergelim){
            if(!c.size()||c.bk!=b[h2]){
                c.pb(b[h2]);
            }
            h2++;
        }
    }
    void cal(){
        dfs(1);
        for(int k=1;k<18;k++){
            for(int i=1;i<=n;i++){
                pa[i][k]=pa[pa[i][k-1]][k-1];
                merge(ls[i][k-1],ls[pa[i][k-1]][k-1],ls[i][k]);
            }
        }
    }
    vector<int> ans,tmp;
    void lca(int x,int y){
        ans.clear();
        if(dep[x]<dep[y]) swap(x,y);
        for(int k=0;k<18;k++){
            if((dep[x]-dep[y])&(1<<k)){
                tmp=ans;
                ans.clear();
                merge(tmp,ls[x][k],ans);
                x=pa[x][k];
            }
        }
        if(x==y){
            tmp=ans;
            ans.clear();
            merge(tmp,ls[x][0],ans);
            return;
        }
        for(int k=18-1;k>=0;k--){
            if(pa[x][k]!=pa[y][k]){
                tmp=ans;
                ans.clear();
                merge(tmp,ls[x][k],ans);
                tmp=ans;
                ans.clear();
                merge(tmp,ls[y][k],ans);
                x=pa[x][k];
                y=pa[y][k];
            }
        }
        tmp=ans;
        ans.clear();
        merge(tmp,ls[x][1],ans);
        tmp=ans;
        ans.clear();
        merge(tmp,ls[y][0],ans);
    }
    int main(){
        //freopen("/home/slyfc/CppFiles/in","r",stdin);
        cin>>n>>m>>q;
        for(int i=0;i<n-1;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            G[x].pb(y);
            G[y].pb(x);
        }
        for(int i=1;i<=m;i++){
            int x;
            scanf("%d",&x);
            if(ls[x][0].size()<10) ls[x][0].pb(i);
        }
    
        cal();
        while(q--){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            lca(x,y);
            printf("%d ",min((int)ans.size(),z));
            for(int i=0;i<min((int)ans.size(),z);i++){
                printf("%d ",ans[i]);
            }
            puts("");
        }
        return 0;    
    }
    View Code

    9  CF 589G

    题目:离线查询一个数列的前n项中比x大的数之和。

    思路:这个题首先要离线排序,天和人都按时间降序,然后注意到如果满足较大的d,那么较小的d一定满足,然后用两个bit维护和和个数。

    /*
    * @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=2e5+300;
    int n,m;
    P t[maxn];
    pair<P,int> c[maxn];
    struct BIT{
        ll a[maxn];
        ll sum(int p){
            ll ans=0;
            while(p>0){
                ans+=a[p];
                p-=p&-p;
            }
            return ans;
        }
        void add(int p,int x){
            while(p<maxn){
                a[p]+=x;
                p+=p&-p;
            }
        }
    }A,B;
    int ans[maxn];
    int main(){
        //freopen("/home/slyfc/CppFiles/in","r",stdin);
        cin>>n>>m;
        for(int i=1;i<=m;i++){
            scanf("%d",&t[i].fs);
            t[i].se=i;
        }
        for(int i=1;i<=n;i++){
            int d,r;
            scanf("%d%d",&d,&r);
            c[i].fs.fs=d;c[i].fs.se=r;
            c[i].se=i;
        }
        sort(t+1,t+m+1,greater<P>());
        sort(c+1,c+n+1,greater<pair<P,int> >());
        int pt=1;
        for(int i=1;i<=n;i++){
            int d=c[i].fs.fs,R=c[i].fs.se;
            while(t[pt].fs>=d&&pt<=m){
                B.add(t[pt].se,t[pt].fs);
                A.add(t[pt].se,1);
                pt++;
            }
            int l=0,r=m;
            while(r-l>1){
                int mid=(l+r)/2;
                if(B.sum(mid)-d*A.sum(mid)>=R){
                    r=mid;
                }else{
                    l=mid;
                }
            }
            if(B.sum(r)-d*A.sum(r)>=R) ans[c[i].se]=r;
            else ans[c[i].se]=0;
        }
        for(int i=1;i<=n;i++){
            cout<<ans[i]<<" ";
        }
        return 0;
    
    }
    View Code
  • 相关阅读:
    ffmpeg rtmp推流 视频转码
    java日志发展史 log4j slf4j log4j2 jul jcl 日志和各种桥接包的关系
    nginx stream 流转发,可以转发rtmp、mysql访问流,转发rtmp、jdbc请求
    java web http 转https 通过nginx代理访问
    linux 服务器磁盘挂载
    novnc 通过websockify代理 配置多点访问
    linux 文件服务 minio 安装部署配置
    AOP实现原理,手写aop
    java 泛型
    JAVA反射getGenericSuperclass()用法
  • 原文地址:https://www.cnblogs.com/Cw-trip/p/4843869.html
Copyright © 2011-2022 走看看