zoukankan      html  css  js  c++  java
  • 9月——都已经9月了还不好好刷题?。。

    题目:在一个串中找到至少出现m次的最长的串。
    思路:直接hash,然后二分答案。
    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    */
    //#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 0.00000001
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxl=4e4+300;
    const ull hash1=123;
    int m;
    char s[maxl];
    ull H[maxl];
    ull xp[maxl];
    ull gethash(int i,int L){
        return H[i]-H[i+L]*xp[L];
    }
    int len;
    map<ull,vector<int> > mp;
    map<ull,int> cont;
    map<ull,vector<int> >::iterator it;
    ull val[maxl];
    bool check(int l){
        for(int i=0;i<len-l+1;i++){
            val[i]=gethash(i,l);
        }
        sort(val,val+len-l+1);
        int c=0;
        for(int i=0;i<len-l+1;i++){
            if(i==0||val[i]!=val[i-1]) c=1;
            if(val[i]==val[i-1]) c++;
            if(c>=m) return true;
        }
        return false;
    }
    void getans(int l){
        mp.clear();
        for(int i=0;i+l<=len;i++){
            mp[gethash(i,l)].pb(i);
        }
    }
    void init(){
        xp[0]=1;
        for(int i=1;i<maxl;i++){
            xp[i]=xp[i-1]*hash1;
        }
    }
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        init();
        while(cin>>m,m){
            scanf("%s",s);
            len=strlen(s);
            H[len]=0;
            for(int i=len-1;i>=0;i--){
                H[i]=H[i+1]*hash1+(ull)s[i];
            }
            int l=0,r=len+1;
            while(r-l>1){
                int mid=(r+l)/2;
                if(check(mid)){
                    l=mid;
                }else{
                    r=mid;
                }
            }
            if(l==0){
                puts("none");
                continue;
            }
            getans(l);
            vector<int> pos;
            for(it=mp.begin();it!=mp.end();it++){
                if(it->se.size()>=m){
                    sort(it->se.begin(),it->se.end());
                    pos.pb(it->se.bk);
                }
            }
            sort(pos.begin(),pos.end());
            printf("%d %d
    ",l,pos.bk);
        }
        return 0;
    }
    View Code

     2 POJ 3613 (经过k条边的最短路

    思路:floyd+倍增(快速幂思想)

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    */
    //#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 0.00000001
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF 1000000000
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxn=1005;
    int N,T,S,E;
    int mp[maxn][maxn];
    int dis[maxn][maxn];
    int tmp[maxn][maxn];
    int v[maxn];
    int num=0;
    void setINF(int a[][maxn]){
        for(int i=0;i<num;i++){
            for(int j=0;j<num;j++){
                a[v[i]][v[j]]=INF;
            }
        }
    }
    void cp(int a[][maxn],int b[][maxn]){
        for(int i=0;i<num;i++){
            for(int j=0;j<num;j++){
                a[v[i]][v[j]]=b[v[i]][v[j]];
            }
        }
    }
    void floyd(int dis[][maxn],int a[][maxn],int b[][maxn]){
        for(int k=0;k<num;k++){
            for(int i=0;i<num;i++){
                for(int j=0;j<num;j++){
                    if(dis[v[i]][v[j]]>a[v[i]][v[k]]+b[v[k]][v[j]]){
                        dis[v[i]][v[j]]=a[v[i]][v[k]]+b[v[k]][v[j]];
                    }
                }
            }
        }
    }
    void solve(){
        while(N){
            if(N&1){
                setINF(tmp);
                floyd(tmp,dis,mp);
                cp(dis,tmp);
            }
            setINF(tmp);
            floyd(tmp,mp,mp);
            cp(mp,tmp);
            N>>=1;
        }
    }
    bool used[maxn];
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        cin>>N>>T>>S>>E;
        for(int i=0;i<maxn;i++){
            for(int j=0;j<maxn;j++){
                mp[i][j]=INF;
            }
        }
        for(int i=0;i<T;i++){
            int a,b,l;
            scanf("%d%d%d",&l,&a,&b);
            if(!used[a])
                v[num++]=a,used[a]=1;
            if(!used[b])
                v[num++]=b,used[b]=1;
            if(mp[a][b]>l){
                mp[a][b]=l;
                mp[b][a]=l;
            }
        }
        setINF(dis);
        for(int i=0;i<num;i++) dis[v[i]][v[i]]=0;
        solve();
        printf("%d
    ",dis[S][E]);
        return 0;
    }
    View Code

    3 CodeForces 25E(kmp

    题目:给出三个字符串,求包含这三个字符串的字符串的最小长度。

    思路:三个字符串全排列一下,计算前一个字符串和后一个字符串的最大重叠部分长度。可以用滚动hash或者kmp。kmp虽然是从头开始匹配的,但是最后得到的状态肯定是最大的匹配长度,所以可以只要看最后的状态就行了。

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    */
    #include <bits/stdc++.h>
    #define pb push_back
    #define se second
    #define fs first
    #define sq(x) (x)*(x)
    #define eps 0.000000001
    #define LB lower_bound
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define bk back()
    #define PB pop_back
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> P;
    
    const int maxl=1e5+3000;
    char s[3][maxl];
    int len[3];
    int f[3][maxl];
    void getFail(char *p,int *f){
        int m=strlen(p);
        f[0]=-1;f[1]=0;
        for(int i=1;i<m;i++){
            int j=f[i];
            while(j&&p[i]!=p[j]) j=f[j];
            f[i+1]=(p[i]==p[j]?j+1:0);
        }
    }
    int getmax(int x,int y){
        int i=0,j=0;
        while(i<len[x]&&j<len[y]){
            if(j==-1||s[x][i]==s[y][j]){
                i++,j++;
            }else{
                j=f[y][j];
            }
        }
        return j;
    }
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("test.in","r",stdin);
        //freopen("test.out","w",stdout);
        for(int i=0;i<3;i++){
            scanf("%s",s[i]);
            len[i]=strlen(s[i]);
        }
        for(int i=0;i<3;i++) getFail(s[i],f[i]);
        int ans=0;
        for(int i=0;i<3;i++){
            for(int j=0;j<3;j++){
                if(i==j) continue;
                for(int k=0;k<3;k++){
                    if(i==k||j==k) continue;
                    int tmp=getmax(i,j);
                    if(tmp==len[j]){
                        tmp+=getmax(i,k);
                    }else{
                        tmp+=getmax(j,k);
                    }
                    ans=max(ans,tmp);
                }
            }
        }
        cout<<len[0]+len[1]+len[2]-ans<<endl;
        return 0;
    }
    View Code

     4 HDU 5348 (欧拉回路,dfs,删边

    题目:给出一个图,要求指定边的方向,使得任意点的出度与入度之差小于等于1.

    思路:首先,这个问题是肯定有解的。对于任意一个度为奇数的点,从该点开始dfs,将经过路径上的边都删掉,直到下一个度数为奇的点为之,此时路径中经过的所有点的度的奇偶性都没有改变,而两端点的度都变为了偶数。这样下去一定可以使得度数全为偶数,并且只有两端点的出入度差为1.然后再跑一遍欧拉回路就可以给所有的边找定方向,由于欧拉回路每次有 出必有进,所以对出入度只差没有影响。

    另外此题在实现上有几个技巧,首先是建图,用数组存边可以使得正向边和反向边相邻,并且可以通过位运算计算。其次,如果采用vector建图的话,删边每次从back删就是O(1),否则会超时(当然也可以写成链表,但是我一般都是用vector)。

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    */
    #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 0.00000001
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF 1000000000
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxe=6e5+300;
    const int maxn=1e5+300;
    struct EDGE{
        int to;
        bool d;
    }es[maxe];
    bool del[maxe];
    int deg[maxn];
    int eh=0;
    int ans[maxe];
    vector<int> G[maxn];
    int T;
    int n,m;
    void init(){
        eh=0;
        for(int i=0;i<=n;i++){
            G[i].clear();
        }
        memset(ans,0,sizeof ans);
        memset(del,0,sizeof del);
        memset(deg,0,sizeof deg);
    }
    void addedge(int from,int to){
        es[eh].to=to;es[eh].d=1;
        G[from].pb(eh++);
        es[eh].to=from;es[eh].d=0; 
        G[to].pb(eh++);
        deg[from]++,deg[to]++;
    }
    set<int> d1;
    void dfs(int v){
        while(!G[v].empty()&&del[G[v].bk]) G[v].PB();
        deg[v]--;
        del[G[v].bk]=del[G[v].bk^1]=1;
        ans[G[v].bk/2]=es[G[v].bk].d;
        int to=es[G[v].bk].to;
        deg[to]--;
        if(deg[to]%2==0){
            d1.erase(to);
            return;
        }
        dfs(to);
    }
    void eular(int v){
        while(!G[v].empty()&&del[G[v].bk]) G[v].PB();
        if(G[v].empty()) return;
        deg[v]--;
        EDGE e=es[G[v].bk];
        del[G[v].bk]=del[G[v].bk^1]=1;
        ans[G[v].bk/2]=e.d;
        deg[e.to]--;
        G[v].PB();
        eular(e.to);
    }
    void solve(){
        d1.clear();
        for(int i=1;i<=n;i++){
            if(deg[i]%2) d1.insert(i);
        }
        while(d1.size()){
            int v=*d1.begin();
            d1.erase(v);
            dfs(v);
        }
        for(int i=1;i<=n;i++){
            if(deg[i]){
                eular(i);
            }
        }
    }
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("defense.in","r",stdin);
        //freopen("defense.out","w",stdout);
        cin>>T;
        while(T--){
            cin>>n>>m;
            init();
            for(int i=0;i<m;i++){
                int u,v;
                scanf("%d%d",&u,&v);
                addedge(u,v);
            }
            solve();
            for(int i=0;i<m;i++){
                printf("%d
    ",ans[i]);
            }
        }
        return 0;
    }
    View Code

     5 HDU 5409(桥,dfs,树形dp

    题目:求一个图中的桥,以及被该桥隔开的点对,要求第一个点的标号尽量大,第二个点的标号尽量小,并且第一个点大于第二个点。

    思路:首先有一个必须要注意到的地方是对于桥而言,两边的点就是所有的点,所以答案必然是没有n的那一边最大的点,以及比这个点大一的点。然后求桥就是直接上tarjan算法,现在问题就是求出一个桥的左右两边最大的点。这个可以通过树形dp求解。对于每一个点,第一遍dfs记录该点的子树包含点的最大值和次大值,第二遍dfs算出这个点通过其父边走到的那一边的最大值,这个要就最大和次大值讨论一下。然后dp的第一次dfs可以和tarjan写在一起,第二次直接求出结果。

    注意这图并不是一棵树,但是可以用一次dfs把它变成一棵树,并且删去不在树上的边(每条边给定一个方向),这样所有的桥必然在树上,并且被该桥分开的双连通分量位于桥的两侧。

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    * 蒟蒻只能做几个水题。。
    */
    //#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 0.00000001
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF 1000000000
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxn=2e5+3000;
    bool del[maxn];
    int es[maxn];
    int eh=0;
    vector<int> G[maxn];
    void addedge(int from,int to){
        es[eh]=to;
        G[from].pb(eh++);
        es[eh]=from;
        G[to].pb(eh++);
    }
    int T,n,m;
    int low[maxn],dfn[maxn],clo,rmax[maxn],smax[maxn],maxid[maxn];
    void tarjan_dfs(int v){
        dfn[v]=low[v]=++clo;
        for(int i=0;i<G[v].size();i++){
            int e=G[v][i];
            if(del[e]) continue;
            int u=es[e];
            del[e^1]=1;
            if(!dfn[u]){
                tarjan_dfs(u);
                low[v]=min(low[v],low[u]);
                if(max(u,rmax[u])>rmax[v]){
                    smax[v]=max(u,rmax[u]);
                    swap(smax[v],rmax[v]);
                    maxid[v]=u;
                }else if(max(u,rmax[u])>smax[v]){
                    smax[v]=max(u,rmax[u]);
                }
            }else{
                low[v]=min(low[v],dfn[u]);
            }
        }
    }
    int ans[maxn][2];
    bool vis[maxn];
    void work(int v,int from,int f){
        vis[v]=1;
        for(int i=0;i<G[v].size();i++){
            int e=G[v][i];
            if(del[e]||vis[es[e]]) continue;
            int u=es[e];
            if(u==maxid[v]){
                if(max(v,smax[v])>smax[u]){
                    smax[u]=max(v,smax[v]);
                }
            }else{
                if(max(v,rmax[v])>smax[u]){
                    smax[u]=max(v,rmax[v]);
                }
            }
            work(u,e,v);
        }
        if(f!=-1&&low[v]==dfn[v]){
            if(max(v,rmax[v])==n){
                ans[from/2][0]=max(f,smax[f]);
                ans[from/2][1]=max(f,smax[f])+1;
            }else{
                ans[from/2][0]=max(v,rmax[v]);
                ans[from/2][1]=max(v,rmax[v])+1;
            }
        }
    }
    void init(){
        clo=eh=0;
        memset(del,0,sizeof del);
        memset(dfn,0,sizeof dfn);
        memset(ans,0,sizeof ans);
        memset(smax,0,sizeof smax);
        memset(rmax,0,sizeof rmax);
        memset(vis,0,sizeof vis);
        for(int i=0;i<=n;i++)
            G[i].clear();
    }
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("defense.in","r",stdin);
        //freopen("defense.out","w",stdout);
        cin>>T;
        while(T--){
            cin>>n>>m;
            init();
            for(int i=0;i<m;i++){
                int a,b;
                scanf("%d%d",&a,&b);
                addedge(a,b);
            }
            tarjan_dfs(1);
            work(1,0,-1);
            for(int i=0;i<m;i++){
                printf("%d %d
    ",ans[i][0],ans[i][1]);
            }
        }
        return 0;
    }
    View Code

     6 PKU 1655(求树的重心,树形dp

    题目:求一个点,以这个点为根的树的最大子树最小。

    思路:简单的树形dp(dfs?),然而看错题wa了半个小时==,题目说要输出number,我以为要输出数量,结果尼玛居然是要输出编号。。。。

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    * 蒟蒻只能做几个水题。。
    */
    //#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 0.00000001
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF 1000000000
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxn=2e4+300;
    int T;
    int n;
    vector<int> G[maxn];
    int ansv,ansn;
    int num1[maxn];
    void init(){
        for(int i=0;i<=n;i++){
            G[i].clear();
        }
        ansn=1e9;
    }
    void dfs(int v,int f){
        num1[v]=1;
        int maxx=0;
        for(int i=0;i<G[v].size();i++){
            int u=G[v][i];
            if(u==f) continue;
            dfs(u,v);
            num1[v]+=num1[u];
            maxx=max(maxx,num1[u]);
        }
        maxx=max(maxx,n-num1[v]);
        if(maxx<ansn){
            ansn=maxx;
            ansv=v;
        }else if(maxx==ansn){
            ansv=v;
        }
    }
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("defense.in","r",stdin);
        //freopen("defense.out","w",stdout);
        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);
            }
            dfs(1,-1);
            printf("%d %d
    ",ansv,ansn);
        }
        return 0;
    }
    View Code

    PKU1741(树分治

    题目:求一棵树上路径长度小于k的路径条数。

    思路:这是LTC的男人八题里比较简单的一道。首先如果不是树,而是链的话,我们可以想到一种分治算法(当然链的情况不分治更快),就是对于一个中点,对答案有贡献的要么是跨越中点的路径,要么是两边的路径,那么每次从中点分开,进行分治的话复杂度是O(nlogn),对于这个树上的情况思路也是一样的,但是树上的分治有个比较特殊的地方是这个中点不太好找,需要跑一次dfs。然后对每个分开的子树递归计算。我的实现总共用了5个递归,似乎可以少用一个(算子树的节点数目的时候),但是没想清楚怎么去,就索性直接又dfs了一遍。

    另外,除了这种点分治,还可以使用边分治,但是边分治有一种难以避免的使复杂度大大增加的情况(处理方法似乎比较复杂),所以树分治的首选还是点分治。

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    * 蒟蒻只能做几个水题。。
    */
    //#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 0.00000001
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF 1000000000
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxn=2e4+300;
    struct EDGE{
        int to,d;
    };
    vector<int> G[maxn];
    EDGE es[maxn];
    int eh;
    int center,mins;
    bool vis[maxn];
    vector<int> dis;
    int n,k;
    int cnt;
    int getCenter(int v,int f){
        int ssum=0,maxs=0;
        for(int i=0;i<G[v].size();i++){
            int e=G[v][i];
            int u=es[e].to;
            if(vis[u]||u==f) continue;
            int aa=getCenter(u,v);
            if(aa>maxs) maxs=aa;
            ssum+=aa;
        }
        if(max(maxs,cnt-ssum-1)<mins){
            center=v;
            mins=max(maxs,cnt-ssum-1);
        }
        return ssum+1;
    }
    void dfs(int v,int fore,int f){
        dis.pb(fore);
        for(int i=0;i<G[v].size();i++){
            int e=G[v][i];
            int u=es[e].to;
            if(vis[u]||u==f) continue;
            dfs(u,fore+es[e].d,v);
        }
    }
    void cont(int v,int f){
        cnt++;
        for(int i=0;i<G[v].size();i++){
            int e=G[v][i];
            int u=es[e].to;
            if(vis[u]||u==f) continue;
            cont(u,v);
        }
    }
    int cul(int v,int fore){
        int ans=0;
        dis.clear();
        dfs(v,fore,-1);
        sort(dis.begin(),dis.end());
        int p=0,q=dis.size()-1;
        while(p<=q){
            while(p<=q&&dis[q]+dis[p]>k) q--;
            if(p>q) break;
            ans+=q-p;
            p++;
        }
        return ans;
    }
    int solve(int v){
        vis[v]=1;
        int ans=0;
        ans+=cul(v,0);
        for(int i=0;i<G[v].size();i++){
            int e=G[v][i];
            int u=es[e].to;
            if(vis[u]) continue;
            ans-=cul(u,es[e].d);
            mins=1e8;
            cnt=0;
            cont(u,-1);
            getCenter(u,-1);
            ans+=solve(center);
        }
        return ans;
    }
    void addedge(int from,int to,int d){
        es[eh].to=to,es[eh].d=d;
        G[from].pb(eh++);
        es[eh].to=from,es[eh].d=d;
        G[to].pb(eh++);
    }
    void init(){
        eh=0;
        for(int i=0;i<=n;i++)
            G[i].clear();
        memset(vis,0,sizeof vis);
        dis.clear();
    }
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("defense.in","r",stdin);
        //freopen("defense.out","w",stdout);
        while(cin>>n>>k){
            if(n==0&&k==0) break;
            init();
            for(int i=0;i<n-1;i++){
                int a,b,c;
                scanf("%d%d%d",&a,&b,&c);
                addedge(a,b,c);
            }
            mins=1e9;
            dfs(1,0,-1);
            cnt=0;
            cont(1,-1);
            getCenter(1,-1);
            cout<<solve(center)<<endl;
        }
        return 0;
    }
    View Code

    PKU 1390(dp,巧妙思维

    题目:若干染了色的盒子排成一排,相同颜色的盒子可以消去,获益为消去的盒子数平方,求最大获益。

    思路:这个解法比较新颖。自己开始看这个题的之后想的是颜色相同的两段配对,然后区间dp,然后自己立马就找了个反例(最后消去的一块可能来自于最初的多个块,而不只是2个)。。然后就不会了。对于dp来说,如果出现解决不了的问题,就可以往升高维数的方向考虑。此题除了区间以外,考虑增加一维,表示最后一位与其后同色的配对有多少个(这种情况对应了消去后面k个同色块之间的其他块的决策),然后对于这种情况,要么在这个位置把积累的k个块连同最后一个块都消掉,要么继续累计,但是这个累计只能累计到前面的某个同色块。所以实际的复杂度远不到O(n^4),这样就可以在时间内解决问题了。

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    * 蒟蒻只能做几个水题。。
    */
    //#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 0.00000001
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF 1000000000
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxn=205;
    int T;
    int n;
    int a[maxn];
    int dp[maxn][maxn][maxn];
    vector<int> num,col;
    int cal(int l,int r,int k){
        if(l==r) return sq(num[l]+k);
        if(dp[l][r][k]!=-1) return dp[l][r][k];
        dp[l][r][k]=0;
        dp[l][r][k]=max(dp[l][r][k],cal(l,r-1,0)+sq(num[r]+k));
        for(int p=l;p<r-1;p++){
            if(col[p]==col[r]&&r-1>=p+1)
                dp[l][r][k]=max(dp[l][r][k],cal(l,p,num[r]+k)+cal(p+1,r-1,0));
        }
        return dp[l][r][k];
    }
    int cas=0;
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("defense.in","r",stdin);
        //freopen("defense.out","w",stdout);
        cin>>T;
        while(T--){
            cin>>n;
            memset(dp,-1,sizeof dp);
            for(int i=1;i<=n;i++){
                scanf("%d",&a[i]);
            }
            num.clear();
            col.clear();
            int last=-1,cont=0;
            for(int i=1;i<=n;i++){
                if(a[i]!=last){
                    if(last!=-1){
                        num.pb(cont);
                        col.pb(last);
                    }
                    cont=1;
                    last=a[i];
                }else{
                    cont++;
                }
            }
            col.pb(last);num.pb(cont);
            int len=col.size();
            printf("Case %d: %d
    ",++cas,cal(0,len-1,0));
        }
        return 0;
    }
    View Code

     注意这题还有个神奇的优化:其实对于把值往前推的操作,值需要计算最近的同色的位置就行了(我得承认这和我想的有点不一样==,但是把break提到外面就wa。。。依然是意义不明。。),然后就可以break,这么搞速度能提升到原来的4倍!!

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    * 蒟蒻只能做几个水题。。
    */
    //#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 0.00000001
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF 1000000000
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxn=205;
    int T;
    int n;
    int a[maxn];
    int dp[maxn][maxn][maxn];
    vector<int> num,col;
    int cal(int l,int r,int k){
        if(l==r) return sq(num[l]+k);
        if(dp[l][r][k]!=-1) return dp[l][r][k];
        dp[l][r][k]=0;
        dp[l][r][k]=max(dp[l][r][k],cal(l,r-1,0)+sq(num[r]+k));
        for(int p=r-2;p>=l;p--){
            if(col[p]==col[r]&&r-1>=p+1){
                int res=cal(l,p,num[r]+k)+cal(p+1,r-1,0);
                if(dp[l][r][k]<res){
                    dp[l][r][k]=res;
                    break;//神剪枝!!。。
                }
            }
        }
        return dp[l][r][k];
    }
    int cas=0;
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("defense.in","r",stdin);
        //freopen("defense.out","w",stdout);
        cin>>T;
        while(T--){
            cin>>n;
            memset(dp,-1,sizeof dp);
            for(int i=1;i<=n;i++){
                scanf("%d",&a[i]);
            }
            num.clear();
            col.clear();
            int last=-1,cont=0;
            for(int i=1;i<=n;i++){
                if(a[i]!=last){
                    if(last!=-1){
                        num.pb(cont);
                        col.pb(last);
                    }
                    cont=1;
                    last=a[i];
                }else{
                    cont++;
                }
            }
            col.pb(last);num.pb(cont);
            int len=col.size();
            printf("Case %d: %d
    ",++cas,cal(0,len-1,0));
        }
        return 0;
    }
    View Code

     9 HDU 5001(概率dp,暴力枚举。

    题目:一个人在图上任意一点开始随机游走d步,问某点未被经过的概率。

    思路:删去一个点,然后计算在不经过该点的情况下最后到达其他点的概率和即是答案。

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    * 蒟蒻只能做几个水题。。
    */
    //#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 0.00000001
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF 1000000000
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    int T;
    double dp[60][10040];
    vector<int> G[60];
    int n,m,d;
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("defense.in","r",stdin);
        //freopen("defense.out","w",stdout);
        cin>>T;
        while(T--){
            cin>>n>>m>>d;
            for(int i=0;i<=n;i++) G[i].clear();
            for(int i=0;i<m;i++){
                int a,b;
                scanf("%d%d",&a,&b);
                G[a].pb(b);
                G[b].pb(a);
            }
            for(int del=1;del<=n;del++){
                memset(dp,0,sizeof dp);
                for(int i=1;i<=n;i++) dp[i][0]=1.0/n;
                for(int s=0;s<d;s++){
                    for(int i=1;i<=n;i++){
                        if(i==del) continue;
                        for(int j=0;j<G[i].size();j++){
                            if(G[i][j]==del) continue;
                            int u=G[i][j];
                            dp[u][s+1]+=dp[i][s]/G[i].size();
                        }
                    }
                }
                double ans=0;
                for(int i=1;i<=n;i++){
                    if(i==del) continue;
                    ans+=dp[i][d];
                }
                printf("%.10f
    ",ans);
            }
        }
        return 0;
    }
    View Code

     10 Ural1519(插头dp

    题目:一个棋盘中有若干障碍,求经过所有非障碍格子的回路数目。

    思路:cdq的论文例题,然而不会写。。。。几乎是照着队友的代码抄了一遍,毫无成就感。。。插头dp。。。一定要再自己写一道。。。。

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    * 蒟蒻只能做几个水题。。
    */
    //#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 0.00000001
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF 1000000000
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const ll hashsize=2e6;
    int n,m;
    int M[30][30];
    int ex,ey;
    int bit[30];
    int hashTab[hashsize];
    int Snum[2];
    ll dp[2][hashsize],ans;
    int state[2][hashsize];
    bool idx;
    void hashCal(ll s,ll num){
        int hashpos=s%hashsize;
        while(hashTab[hashpos]!=-1){
            if(state[idx][hashTab[hashpos]]==s){
                dp[idx][hashTab[hashpos]]+=num;
                return;
            }
            hashpos++;
            if(hashpos==hashsize) hashpos=0;
        }
        hashTab[hashpos]=Snum[idx]++;
        state[idx][hashTab[hashpos]]=s;
        dp[idx][hashTab[hashpos]]=num;
    }
    void plug_dp(){
        for(int i=1;i<=n;i++){
            for(int k=0;k<Snum[idx];k++) state[idx][k]<<=2;
            for(int j=1;j<=m;j++){
                idx^=1;
                Snum[idx]=0;
                memset(hashTab,-1,sizeof hashTab);
                for(int k=0;k<Snum[1^idx];k++){
                    int s=state[1^idx][k];
                    int p=(s>>bit[j-1])%4;
                    int q=(s>>bit[j])%4;
                    ll num=dp[idx^1][k];
                    if(!M[i][j]){
                        if(!p&&!q){
                            hashCal(s,num);
                        }
                    }else if(!p&&!q){
                        if(M[i+1][j]&&M[i][j+1]){
                            s+=(1<<bit[j-1])+(2<<bit[j]);
                            hashCal(s,num);
                        }
                    }else if(!p&&q){
                        if(M[i][j+1]) hashCal(s,num);
                        if(M[i+1][j]){
                            s+=(q<<bit[j-1])-(q<<bit[j]);
                            hashCal(s,num);
                        }
                    }else if(p&&!q){
                        if(M[i+1][j]) hashCal(s,num);
                        if(M[i][j+1]){
                            s+=(p<<bit[j])-(p<<bit[j-1]);
                            hashCal(s,num);
                        }
                    }else if(p+q==2){
                        int b=1;
                        for(int t=j+1;t<=m;t++){
                            int v=(s>>bit[t])%4;
                            if(v==1) b++;
                            if(v==2) b--;
                            if(b==0){
                                s-=(1<<bit[t]);
                                break;
                            }
                        }
                        s-=(1<<bit[j-1])+(1<<bit[j]);
                        hashCal(s,num);
                    }else if(p+q==4){
                        int b=1;
                        for(int t=j-2;t>=0;t--){
                            int v=(s>>bit[t])%4;
                            if(v==2) b++;
                            else if(v==1) b--;
                            if(b==0){
                                s+=(1<<bit[t]);
                                break;
                            }
                        }
                        s-=(2<<bit[j-1])+(2<<bit[j]);
                        hashCal(s,num);
                    }else if(p==2&&q==1){
                        s-=(2<<bit[j-1])+(1<<bit[j]);
                        hashCal(s,num);
                    }else if(p==1&&q==2){
                        if(i==ex&&j==ey){
                            ans+=num;
                        }
                    }
                }
            }
        }
    }
    void init(){
        for(int i=0;i<=15;i++)
            bit[i]=i<<1;
        dp[0][0]=1;
        Snum[0]=1;
    }
    void read(){
        char r[30];
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            scanf("%s",r);
            for(int j=1;j<=m;j++){
                if(r[j-1]=='*'){
                    M[i][j]=0;
                }else{
                    M[i][j]=1;
                    ex=i,ey=j;
                }
            }
        }
    }
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("defense.in","r",stdin);
        //freopen("defense.out","w",stdout);
        init();
        read();
        plug_dp();
        cout<<ans<<endl;
        return 0;
    }
    View Code

     11 POJ 3635(最短路

    题目:每个城市的油价不同,走一单位距离要消耗一单位油,油箱上限为c,问从s到e的最小花费。

    思路:我们可以增加一维,用dis[i][j]表示在城市i有j的油量时的花费,然后这个题就转换成了1e5个点的最短路。但是我一开始写错了,原因是这题要求的到e的最短路,而不是到所有点的最短路,那么首先扩展的时候,每一个点只需要增加1的油量(这是离这个点最近的点,再增加油量的时候等到下次扩展)。另外一旦扩展到了e,立即退出,此时e点必然是最短路,如果不退出势必会把所有点的满油量情况都试遍,虽然对于最坏情况两种写法是一样的,但是对于随机情况效率提升是非常大的。

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    * 蒟蒻只能做几个水题。。
    */
    //#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-3)
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF 1000000000
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    
    const int maxn=1005;
    struct EDGE{
        int to,d;
        EDGE(int to,int d):to(to),d(d){}
    };
    struct A{
        int v,has,cost;
        bool operator < (const A &C)const{
            return cost>C.cost;
        }
        A(int v,int has,int cost):v(v),has(has),cost(cost){}
    };
    vector<EDGE> G[maxn];
    priority_queue<A> Q;
    int n,m;
    int cost[maxn][105];
    int p[maxn];
    int c,s,e;
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("defense.in","r",stdin);
        //freopen("defense.out","w",stdout);
        cin>>n>>m;
        for(int i=0;i<n;i++){
            scanf("%d",&p[i]);
        }
        for(int i=0;i<m;i++){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            G[a].pb(EDGE(b,c));
            G[b].pb(EDGE(a,c));
        }
        int q;
        cin>>q;
        while(q--){
            int cont=0;
            while(!Q.empty()) Q.pop();
            scanf("%d%d%d",&c,&s,&e);
            memset(cost,0x3f,sizeof cost);
            cost[s][0]=0;
            Q.push(A(s,0,0));
            bool f=0;
            int ans;
            while(!Q.empty()){
                cont++;
                A now=Q.top();Q.pop();
                int v=now.v,t=now.has;
                if(v==e) break;
                if(cost[v][t]<now.cost) continue;
                if(t+1<=c){
                    if(cost[v][t+1]>cost[v][t]+p[v]){
                        cost[v][t+1]=cost[v][t]+p[v];
                        Q.push(A(v,t+1,cost[v][t]+p[v]));
                    }
                }
                for(int i=0;i<G[v].size();i++){
                    EDGE &e=G[v][i];
                    if(t>=e.d){
                        if(cost[e.to][t-e.d]>cost[v][t]){
                            cost[e.to][t-e.d]=cost[v][t];
                            Q.push(A(e.to,t-e.d,cost[e.to][t-e.d]));
                        }
                    }
                }
            }
            if(cost[e][0]<1e8)
                printf("%d
    ",cost[e][0]);
            else 
                puts("impossible");
        }
        return 0;
    }
    View Code

     12 ZOJ 3820(树的直径,二分

    题目:求两点使得树上任意一点到这两点的最短距离中最长的最短。

    思路:二分答案,可以注意到这两点在树的直径上肯定是最优的,bfs判定一下即可。

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    * 蒟蒻只能做几个水题。。
    */
    //#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 0.00000001
    #define IINF (1<<29)
    #define LINF (1ll<<59)
    #define INF 1000000000
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    typedef pair<ll,ll> P;
    
    const int maxn=2e5+300;
    int n;
    vector<int> G[maxn];
    int dis[maxn];
    vector<int> D;
    bool mark[maxn];
    void bfs(int s){
        memset(dis,-1,sizeof dis);
        queue<int> Q;
        dis[s]=0;
        Q.push(s);
        while(!Q.empty()){
            int v=Q.front();
            Q.pop();
            for(int i=0;i<G[v].size();i++){
                int u=G[v][i];
                if(dis[u]==-1){
                    dis[u]=dis[v]+1;
                    Q.push(u);
                }
            }
        }
    }
    void getD(int v,int maxp){
        D.clear();
        while(1){
            D.pb(v);
            if(v==maxp) break;
            for(int i=0;i<G[v].size();i++){
                int u=G[v][i];
                if(dis[u]+1==dis[v]){
                    v=u;
                    break;
                }
            }
        }
    }
    bool vis[maxn];
    void bfs_mark(int v,int rem){
        queue<P> Q;
        Q.push(P(v,rem));
        while(!Q.empty()){
            int u=Q.front().fs;
            int r=Q.front().se;
            mark[u]=1,vis[u]=1;
            Q.pop();
            for(int i=0;i<G[u].size();i++){
                int uu=G[u][i];
                if(!vis[uu]){
                    if(r>0)
                        Q.push(P(uu,r-1));
                }
            }
        }
    }
    int ans[2];
    bool check(int p){
        if(p>=D.size()-1){
            ans[0]=1;
            ans[1]=2;
            return 1;
        }
        ans[0]=D[p];
        ans[1]=D[D.size()-1-p];
        if(ans[1]==ans[0]){
            ans[1]=D[p-1];
        }
        memset(mark,0,sizeof mark);
        memset(vis,0,sizeof vis);
        bfs_mark(ans[0],p);
        memset(vis,0,sizeof vis);
        bfs_mark(ans[1],p);
        for(int i=1;i<=n;i++){
            if(!mark[i]) return 0;
        }
        return 1;
    }
    int T;
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("defense.in","r",stdin);
        //freopen("defense.out","w",stdout);
        cin>>T;
        while(T--){
            cin>>n;
            for(int i=0;i<=n;i++)
                G[i].clear();
            for(int i=0;i<n-1;i++){
                int a,b;
                scanf("%d%d",&a,&b);
                G[a].pb(b);
                G[b].pb(a);
            }
            if(n==2){
                puts("0 1 2");
                continue;
            }
            bfs(1);
            int maxd=0,maxp=0;
            for(int i=1;i<=n;i++){
                if(dis[i]>maxd){
                    maxd=dis[i];
                    maxp=i;
                }
            }
            bfs(maxp);
            maxd=0;
            int maxs=0;
            for(int i=1;i<=n;i++){
                if(dis[i]>maxd){
                    maxd=dis[i];
                    maxs=i;
                }
            }
            getD(maxs,maxp);
            int l=0,r=n-1;
            while(r-l>1){
                int mid=(r+l)/2;
                if(check(mid)){
                    r=mid;
                }else{
                    l=mid;
                }
            }
            check(r);
            printf("%d %d %d
    ",r,ans[0],ans[1]);
        }
        return 0;
    }
    View Code

     13 PKU 3071(概率dp

    题目:足球赛,每次比赛与相邻的球队进行,胜出的晋级。问最后获胜希望最大的球队是哪只。

    思路:dp[i][j]=第i轮第j只球队胜出的概率,注意到每轮每只球队只能与特定范围内的球队比赛。

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    * 蒟蒻只能做几个水题。。
    */
    //#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 maxn=1<<10;
    int n;
    double p[maxn][maxn];
    double dp[30][maxn];
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("defense.in","r",stdin);
        //freopen("defense.out","w",stdout);
        while(cin>>n){
            if(n==-1) break;
            int num=(1<<n);
            for(int i=0;i<num;i++){
                for(int j=0;j<num;j++){
                    scanf("%lf",&p[i][j]);
                }
            }
            memset(dp,0,sizeof dp);
            for(int i=0;i<num;i++) 
                dp[0][i]=1;
            for(int k=1;k<=n;k++){
                int rd=1<<k;
                for(int i=0;i<num;i++){
                    for(int j=i/rd*rd;j<i/rd*rd+rd;j++){
                        if(j/(rd/2)==i/(rd/2)) continue;
                        dp[k][i]+=dp[k-1][i]*dp[k-1][j]*p[i][j];
                    }
                }
            }
            double maxx=0;
            int ans=0;
            for(int i=0;i<num;i++){
                if(dp[n][i]>maxx){
                    maxx=dp[n][i];
                    ans=i;
                }
            }
            cout<<ans+1<<endl;
        }
        return 0;
    }
    View Code

     14 SGU 495

    题目:每次在n个盒子中随机选一个,选m次后没被选中的盒子期望个数是多少?

    思路:由于每个盒子是一样的,那么这个盒子被选中的期望次数就是它被选中的概率(1减一下即可),然后总的期望次数就是乘n。

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    * 蒟蒻只能做几个水题。。
    */
    //#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;
    
    int n,m;
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("defense.in","r",stdin);
        //freopen("defense.out","w",stdout);
        while(cin>>n>>m){
            double ans=1;
            for(int i=1;i<=m;i++){
                ans*=((double)(n-1)/n);
            }
            ans=1-ans;
            printf("%.14f",ans*n);
        }
        return 0;
    }
    View Code

     15 ZOJ 3329

    题目:置三个色子,每次如果分别等于abc,就分数置零,否则加上掷出的点数,达到n以上退出,问期望步数。

    思路:设出dp【0】然后方程变形一下可发现规律,参照:http://blog.csdn.net/xingyeyongheng/article/details/25639827

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    * 蒟蒻只能做几个水题。。
    */
    //#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-19)
    #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;
    
    int T;
    int n,k[3],h[3];
    int tol;
    double A[600],B[600];
    void dfs(int v){
        //cout<<v<<endl;
        if(A[v]>0) return;
        if(v>n) return;
        for(int i=1;i<=k[0];i++){
            for(int j=1;j<=k[1];j++){
                for(int m=1;m<=k[2];m++){
                    dfs(v+i+j+m);
                    if(i==h[0]&&j==h[1]&&m==h[2]) continue;
                    A[v]+=A[v+i+j+m]/tol;
                    B[v]+=B[v+i+j+m]/tol;
                }
            }
        }
        A[v]+=1.0/tol;
        B[v]+=1;
    }
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("defense.in","r",stdin);
        //freopen("defense.out","w",stdout);
        cin>>T;
        while(T--){
            tol=1;
            cin>>n;
            memset(A,0,sizeof A);
            memset(B,0,sizeof B);
            for(int i=0;i<3;i++){
                scanf("%d",&k[i]);
                tol*=k[i];
            }
            for(int i=0;i<3;i++){
                scanf("%d",&h[i]);
            }
            dfs(0);
            printf("%.15f
    ",B[0]/(1-A[0]));
        }
        return 0;
    }
    View Code

     16 HDU.4089(概率dp好题

    题目:有n个人排名激活网游,我目前在第m位,对于每个人,有可能服务器出故障,他就得从最后开始继续排,或者他激活成功了,那么就出队。还有一种可能是系统直接崩溃,队里的人都激活不了了。。。现在我觉得如果我都排到前k了,结果系统崩溃了,这就是一件很坑爹的事情,问坑爹的概率。。。

    思路:这题连kuangbin大神都说难啊。。。(hdu莫名奇妙改了这题的内存,导致以前能a的代码基本都a不了了。。虽然滚动一下很简单但是我莫名就是过不了,然后也不想再耗时间了。。。。)首先dp的状态就是有i个人,目前排在第j位,到达目标状态的概率。转移方程还是很清楚,但是我们会发现转移会出现环。联想到之前设出一个值的做法呢?(脑洞不足。。。)但是这题是可以递推的,首先在转移中涉及i-1的部分是已经求得的。对于i的部分,涉及的是j-1的值,直接转移会遇到1然后再要求最后一位的值的情况。但是我们可以把这个情况变换为之前求得的值。基本的想法是这样的:我们考虑减少人数(只有当有人激活成功的时候人数才会减少,同时考虑正好到某人崩溃的情况,注意只考虑一圈,因为最终跳出的情况对应了这一轮必然发生了某种变化),那么可以枚举第一个激活成功的人的位置,可能是第1到第i-1个人,让这个人激活之后就转换成了i-1的情况。还有一种情况就是我到了第1,然后正好gg了(这种情况对应了人数始终没有减少),如果人数一直没有减少,转了一圈也没有gg,那么就回到了开始的情况(我们求解要避免这种无意义的循环)。这样就可以求的我排在最后的情况,然后求得在第一的情况,问题顺利解决。

    /*
    * @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-9)
    #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 maxn=2005;
    int N,M,K;
    double p1,p2,p3,p4;
    double dp[2][maxn];
    double c[maxn];
    double pp[maxn];
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("defense.in","r",stdin);
        //freopen("defense.out","w",stdout);
        while(scanf("%d%d%d%lf%lf%lf%lf",&N,&M,&K,&p1,&p2,&p3,&p4)!=EOF){
            if(p4<eps){
                puts("0.00000");
                continue;
            }
            memset(dp,0,sizeof dp);
            memset(c,0,sizeof c);
            memset(pp,0,sizeof pp);
            bool f=0;
            double p=p2/(1-p1);
            double p33=p3/(1-p1);
            double p44=p4/(1-p1);
            dp[f][1]=p44/(1-p);
            c[1]=p44;
            pp[0]=1.0;
            for(int i=1;i<=N;i++) pp[i]=p*pp[i-1];
            for(int i=2;i<=N;i++){
                for(int j=2;j<=K;j++) c[j]=p33*dp[f][j-1]+p44;
                for(int j=K+1;j<=i;j++) c[j]=p33*dp[f][j-1];
                double tmp=c[1]*pp[i-1];
                for(int j=2;j<=K;j++) tmp+=c[j]*pp[i-j];
                for(int j=K+1;j<=i;j++) tmp+=c[j]*pp[i-j];
                dp[f^1][i]=tmp/(1-pp[i]);
                dp[f^1][1]=p44+dp[f^1][i]*p;
                for(int j=2;j<i;j++){
                    dp[f^1][j]=c[j]+dp[f^1][j-1]*p;
                }
                f^=1;
            }
            printf("%.5f
    ",dp[f][M]);
        }
        return 0;
    }
    View Code

    (并未ac)基本与kuangbin大神一致http://www.cnblogs.com/kuangbin/archive/2012/10/03/2710987.html

    17 HDU 5442(最小表示法,后缀数组,kmp,二分

    题目:求出一个串的最大表示,要求1)如果最大表示是唯一的,输出起始位置和方向2)如果有两种一样的,那么输出起始位置小的3)如果起始位置也一样,输出正向的。

    思路:弱不会做。。。看了几份代码,大概有两种思路,一种是求出后缀数组后乱搞,一种是最小表示法。

    本来想最小表示法是比较裸的,写了一发后发现并不是这样。最小表示法求出的是最小串的最小起始位置,对于正向而言这个结果正是想要的,但是逆向跑一遍就会发现求出的是(原串中)最后的位置。最小表示法求解主要就要解决这个问题。

    我看到两种搞法,一种是kmp,一种是二分(如果把起始位置往后推,最小表示还能在后面找到的话,最小起始位置就比当前位置小)。

    二分感觉是挺自然的一种想法,速度也不差(佩服啊),kmp可以找匹配的最后位置,这个应该是非常重要的一个应用。

    (代码还没写。。。)

    UPD:第一次写完之后不明原因一直T,,,,遂放弃,今天又写了一遍还是T...简直日狗...然后终于发现hdu的strcat不能copy自己......但是本地运行好好的....

    /*
    * @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 maxlen=1e5+30000;
    char r[maxlen];
    char min1[maxlen],min2[maxlen];
    char tmp[maxlen];
    char rev[maxlen];
    int fail[maxlen];
    void getNext(char *s,int *fail,int len){
        int i=0,j=fail[0]=-1;
        while(i<len){
            while(j!=-1&&s[i]!=s[j]) j=fail[j];
            fail[++i]=++j;
        }
    }
    
    int MinimumRepresentation2(char *s,int len){    
        int i=0,j=1,k=0;
        while(i<len&&j<len&&k<len){
            int tag=s[(j+k)%len]-s[(i+k)%len];
            if(tag==0){
                k++;
                continue;
            }
            if(tag<0)
                j+=k+1;
            else
                i+=k+1;
            if(i==j) j++;
            k=0;
        }
        return min(i,j); 
    }
    
    int T;
    int n;
    int main(){
    freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("test.in","r",stdin);
        //freopen("test.out","w",stdout);
        cin>>T;
        while(T--){
            cin>>n;
            scanf("%s",r);
            strcpy(rev,r);
            int len=n;
            for(int i=0;i<n-i-1;i++){
                swap(rev[i],rev[n-i-1]);
            }
            for(int i=len;i<len*2;i++){
                rev[i]=rev[i-len];
            }
            rev[len*2]=0;
            int p1=MinimumRepresentation2(r,len);
            for(int i=0;i<len;i++){
                min1[i]=r[(i+p1)%len];
            }
            min1[len]=0;
            int p2=MinimumRepresentation2(rev,len);
            for(int i=0;i<len;i++){
                min2[i]=rev[(i+p2)%len];
            }
            min2[len]=0;
            getNext(min2,fail,len);
            int i=0,j=0;
            int last=0;
            while(i<len*2-1){
                if(j==-1||min2[j]==rev[i]) i++,j++;
                else j=fail[j];
                if(j==len){
                    last=i-len;
                }
            }
            int d=strcmp(min1,min2);
            if(d>0){
                printf("%d 0
    ",p1+1);
            }else if(d<0){
                printf("%d 1
    ",len-last);
            }else{
                if(p1+1<=len-last){
                    printf("%d 0
    ",p1+1);
                }else{
                    printf("%d 1
    ",len-last);
                }
            }
        }
        return 0;
    }
    View Code

    18 CF 578/C

    题目:求一个x使得数列ai-x的最大连续和的绝对值最小。

    思路:裸三分,比赛的时候被卡精度简直郁闷。。。题解还说了一种方法,感觉很巧妙:构造若干条直线,然后对应每个x的这个pron值就是对应的最高点和最低点之差,然后可以O(n)构造凸包(好像不是凸的?)求解。

    http://codeforces.com/blog/entry/20368

    19 HDU4219(概率dp

    题目:给出一个树,随机指定树上边的长度,问最终树上任意两点间的距离不超过s的概率.

    思路:dp状态为dp[i][j]表示第i个节点下的最长链长度为j时(子树内长度都不超过s的)概率.

    /*
    * @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 maxlen=520;
    const int maxn=70;
    int T,n,l,s;
    vector<int> G[maxn];
    double dp[maxn][maxlen];
    double tmp[maxlen];
    double tmp2[maxlen];
    double prob;
    void dfs(int v,int f){
        if(f!=-1&&G[v].size()==1){
            dp[v][0]=1;
            return;
        }
        dp[v][0]=-1;
        for(int i=0;i<G[v].size();i++){
            int u=G[v][i];
            if(u==f) continue;
            dfs(u,v);
            memset(tmp,0,sizeof tmp);
            for(int j=0;j<=s;j++){
                for(int a=0;a<=l;a++){
                    if(j+a<=s){
                        tmp[j+a]+=prob*dp[u][j];
                    }
                }
            }
            if(dp[v][0]==-1){
                for(int j=0;j<=s;j++){
                    dp[v][j]=tmp[j];
                }
            }else{
                memset(tmp2,0,sizeof tmp2);
                for(int j=0;j<=s;j++){
                    for(int k=0;k<=s;k++){
                        if(k+j>s) break;
                        tmp2[max(k,j)]+=dp[v][j]*tmp[k];
                    }
                }
                for(int j=0;j<=s;j++){
                    dp[v][j]=tmp2[j];
                }
            }
        }
    }
    void init(){
        for(int i=0;i<=n;i++){
            G[i].clear();
        }
    }
    int cas=0;
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("test.in","r",stdin);
        //freopen("test.out","w",stdout);
        cin>>T;
        while(T--){
            cin>>n>>l>>s;
            init();
            memset(dp,0,sizeof dp);
            for(int i=0;i<n-1;i++){
                int a,b;
                scanf("%d%d",&a,&b);
                G[a].pb(b);
                G[b].pb(a);
            }
            prob=1.0/(l+1);
            dfs(1,-1);
            double ans=0;
            for(int i=0;i<=s;i++){
                ans+=dp[1][i];
            }
            printf("Case %d: %.6f
    ",++cas,ans);
        }
        return 0;
    }
    View Code

     20 HDU4169(树形背包

    题目:在一个树上选k个点,使得没有任何一点是另一点的祖先.求最大权值.

    思路:挺简单的一道dp,但是首先不能开全局数组,会爆内存.其次,有一个很关键的优化,就是在子树中可能节点个数达到k的是很少的,所以要记录一下节点个数上限,这个优化可以从tle优化到只有1400ms..

    /*
    * @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 maxn=2e5;
    int n,k;
    vector<int> G[maxn];
    int a[maxn];
    int tmp[305];
    int dfs(int v){
        int dp[305];
        memset(dp,-1,sizeof dp);
        dp[0]=0;
        for(int i=0;i<G[v].size();i++){
            int u=G[v][i];
            int num=dfs(u);
            for(int x=k;x>=0;x--){
                for(int j=1;j<=num;j++){
                    if(j+x<=k&&dp[x]!=-1&&tmp[j]!=-1){
                        dp[j+x]=max(dp[j+x],dp[x]+tmp[j]);
                    }
                }
            }
        }
        dp[1]=max(dp[1],a[v]);
        for(int i=0;i<=k;i++){
            tmp[i]=dp[i];
        }
        for(int i=0;i<=k;i++){
            if(dp[i]==-1){
                return i;
            }
        }
    }
    void init(){
        for(int i=0;i<=n;i++){
            G[i].clear();
        }
    }
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        //freopen("test.in","r",stdin);
        //freopen("test.out","w",stdout);
        while(cin>>n>>k){
            init();
            for(int i=1;i<=n;i++){
                int x;
                scanf("%d%d",&x,&a[i]);
                G[x].pb(i);
            }
            dfs(0);
            if(tmp[k]==-1){
                puts("impossible");
            }else{
                printf("%d
    ",tmp[k]);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    【Java-JVM】定量分析解决OutOfMemoryError: PermGen space, 来看科学量化分析
    Oracle11g 主机身份证明问题
    html标签的嵌套规则
    提高程序员职场价值的10大技巧
    IT人应当知道的10个行业小内幕
    趣文:如果编程语言是车
    去除inline-block元素间间距的N种方法
    《大型网站SEO优化实践》学习分享
    如何通过预加载器提升网页加载速度
    网页爬虫及其用到的算法和数据结构
  • 原文地址:https://www.cnblogs.com/Cw-trip/p/4780036.html
Copyright © 2011-2022 走看看