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
  • 相关阅读:
    CSS箭头
    rails 路由正则表达式
    centos6.7 配置MongoDB日志
    centos6.7 配置Elasticsearch
    拼音纠错
    Pandas学习笔记
    WebService using Spring throwed org.xml.sax.SAXException: Bad envelope tag: htm
    怎样让Windows任务管理器CPU占用率呈现正玄曲线(解释+C#实现)
    Deepin Linux获得关注,国产GUI值得提倡
    Swing组件的另类嵌套
  • 原文地址:https://www.cnblogs.com/Cw-trip/p/4843869.html
Copyright © 2011-2022 走看看