寒假做题记录

1/11:

   树形DP+tarjan缩环:http://codeforces.com/contest/467/problem/D

     题意是给n个字符串,再给m个转换,要求对n个字符串任意转换,使得最后n个串中r的数量最小,不区分大小写

     输出r最小能有几个,满足条件的n个串的最小长度

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
const long long INF = 1e18+1LL;
const double Pi = acos(-1.0);
const int N = 1e6+10, M = 1e3+20, mod = 1e9+7, inf = 2e9+10;

map<string , int> mp;
int n,cnt,m,tt = 2,b[N];
char a[N],fi[N],se[N];
pair<int,int > p[N],F[N],P[N];
vector<int > G[N];
int head[N],low[N],dfn[N],tot,top,q[N],vis[N],inq[N],scc,belong[N];
struct ss{int to,next;}e[N * 2];
void add(int u,int v) {
    e[tt].next = head[u];
    e[tt].to = v;
    head[u] = tt++;
}
void tarjan(int u) {
        dfn[u] = low[u] = ++tot;
        q[++top] = u; vis[u] = inq[u] = 1;
        for(int i = head[u]; i; i = e[i].next) {
            int to = e[i].to;
            if(!dfn[to]) {
                tarjan(to);
                low[u] = min(low[u],low[to]);
            } else if(inq[to]) low[u] = min(low[u],dfn[to]);
        }
        if(low[u] == dfn[u]) {
            scc++;
            do{
                inq[q[top]] = 0;
                belong[q[top]] = scc;
            } while(u != q[top--]);
        }
}
void update(int u,pair<int ,int > now) {
        if(now.first < P[u].first)
                P[u] = now;
        else if(now.first == P[u].first && P[u].second > now.second)
                P[u] = now;
}
void dfs(int u) {
    vis[u] = 1;
    for(int i = 0; i < G[u].size(); ++i) {
        int to = G[u][i];
        if(vis[to]) {
           update(u,P[to]);continue;
        }
        dfs(to);
        update(u,P[to]);
    }
}
int main() {
        scanf("%d",&n);
        for(int i = 1; i <= n; ++i) {
            scanf("%s",a);
            for(int j = strlen(a)-1; j >= 0; --j)
                a[j] = a[j] >= 'A' && a[j] <= 'Z' ? (a[j] - 'A' + 'a') : a[j];
            int sum = 0;
            for(int j = strlen(a)-1; j >= 0; --j)
                if(a[j] == 'r') sum++;
            if(!mp[a]) mp[a] = ++cnt,p[cnt] = MP(sum,strlen(a));
            b[i] = mp[a];
        }
        scanf("%d",&m);
        for(int i = 1; i <= m; ++i) {
            scanf("%s%s",fi,se);
            for(int j = strlen(fi)-1; j >= 0; --j)
                fi[j] = fi[j] >= 'A' && fi[j] <= 'Z' ? (fi[j] - 'A' + 'a') : fi[j];
            int sum = 0,sum2 = 0;
            for(int j = strlen(fi)-1; j >= 0; --j)
                if(fi[j] == 'r') sum++;
            for(int j = strlen(se)-1; j >= 0; --j)
                se[j] = se[j] >= 'A' && se[j] <= 'Z' ? (se[j] - 'A' + 'a') : se[j];
            for(int j = strlen(se)-1; j >= 0; --j)
                if(se[j] == 'r') sum2++;
            if(!mp[fi]) mp[fi] = ++cnt, p[cnt] = MP(sum,strlen(fi));
            if(!mp[se]) mp[se] = ++cnt, p[cnt] = MP(sum2,strlen(se));
            add(mp[fi],mp[se]);
        }

        for(int i = 1; i <= cnt; ++i) if(!dfn[i]) tarjan(i);
        for(int i = 1; i <= scc; ++i) P[i] = MP(inf,inf);
        for(int i = 1; i <= cnt; ++i)  update(belong[i],p[i]);
        for(int i = 1; i <= cnt; ++i)
            for(int j = head[i]; j; j = e[j].next)
                if(belong[i]!=belong[e[j].to]) {
                    G[belong[i]].push_back(belong[e[j].to]);
            }

        memset(vis,0,sizeof(vis));
        for(int i = 1; i <= scc; ++i) {
            if(!vis[i]) dfs(i);
        }
        LL l = 0, r = 0;
        for(int i = 1; i <= n; ++i) {
            l += P[belong[b[i]]].first;
            r += P[belong[b[i]]].second;
        }
        cout<<l<<" "<<r<<endl;
        return 0;
}
View Code

 1/12:

  tyvj1982:http://www.tyvj.cn/p/1982 基础费用流

  HDU5647:很好的一道树DP,分析可以看http://blog.csdn.net/snowy_smile/article/details/50935295

 

1/15:

  网络流24题:餐巾计划问题       费用流

  建模方法:

  每天用完的餐巾纸和要用的餐巾纸是要分开来的

  造一个源点S,Yi表示每天需要的用量,Xi表示每天用完的餐巾纸,那么S连向每一个Xi并用ri限制,每一个Yi连向T用ri限制

  每天用完的餐巾可以选择留到下一天(Xi->Xi+1),不需要花费,

  送到快洗部(Xi->Yi+m),费用为f,送到慢洗部(Xi->Yi+n),费用为s。

  每天需要的餐巾除了刚刚洗好的餐巾,还可能是新购买的(S->Yi),费用为p。

      网络流24题:负载平衡问题     费用流

  【建模分析】

  计算出每个仓库的盈余后,可以把问题转化为供求问题。

  建立供求网络,把二分图X集合中所有节点看做供应节点,Y集合所有节点看做需求节点,在能一次搬运满足供需的Xi和Yj之间连接一条费用为1的有向边,表示搬运一个单位货物费用为1。

  另外还要在Xi与相邻的Xj之间连接边,表示货物可以暂时搬运过去,不立即满足需求,费用也为1。最大流满足了所有的盈余和亏损供求平衡,最小费用就是最少搬运量。

  网络流24题:分配问题  

  HDU5644:拆点的费用流

  建模分析:先在将每个点拆成工作前(xi)工作后(yi)两点。

  不考虑休假方式:s到y1连容量为k费用0的边,yi到t连容量为p[i]费用为0的边,yi到yi+1连容量为INF费用为0的边,第P个点以后连s到yi容量为INF费用为Q的边。

  考虑休假方式:s到xi连容量为p[i]费用为0的边  表示每天能够过休假的人,xi到yi+tj连容量为INF费用为sj的边  表示休假后继续工作。

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
const long long INF = 1e18+1LL;
const double Pi = acos(-1.0);
const int N = 1e6+10, M = 1e3+20, mod = 1e9+7, inf = 2e9+10;

int S,T,ans1;
int P[N],m,p,Q,s,t;
int n,k,head[40005],q[40005],dis[40005],from[40005],a[40005],cnt=1,sum,ans;
bool inq[40005];
struct data{int from,to,next,v,c;}e[100001];
void ins(int u,int v,int w,int c)
{
    cnt++;
    e[cnt].from=u;e[cnt].to=v;
    e[cnt].v=w;e[cnt].c=c;
    e[cnt].next=head[u];head[u]=cnt;
}
void insert(int u,int v,int w,int c)
{ins(u,v,w,c);ins(v,u,0,-c);}
bool spfa()
{
    for(int i=0;i<=T;i++)dis[i]=inf;
    int t=0,w=1,i,now;
    dis[0]=q[0]=0;inq[0]=1;
    while(t!=w)
    {
        now=q[t];t++;if(t==20001)t=0;
        for(int i=head[now];i;i=e[i].next)
        {
            if(e[i].v&&dis[e[i].to]>dis[now]+e[i].c)
            {
                from[e[i].to]=i;
                dis[e[i].to]=dis[now]+e[i].c;
                if(!inq[e[i].to])
                {
                    inq[e[i].to]=1;
                    q[w++]=e[i].to;
                    if(w==20001)w=0;
                }
            }
        }
        inq[now]=0;
    }
    if(dis[T]==inf)return 0;return 1;
}
void mcf()
{
    int i,x=inf;
    i=from[T];
    while(i)
    {
        x=min(e[i].v,x);
        i=from[e[i].from];
    }
    i=from[T];
    ans1+=x;
    while(i)
    {
        e[i].v-=x;
        e[i^1].v+=x;
        ans+=x*e[i].c;
        i=from[e[i].from];
    }
}
int main() {

    int cas = 1;
    scanf("%d",&cas);
    while(cas--) {
        scanf("%d%d",&n,&k);
        S = 0 , T = 2*n+1;sum=0;
        cnt  =  1;memset(head,0,sizeof(head));
        for(int i = 1; i <= n; ++i)scanf("%d",&P[i]),sum+=P[i],insert(i+n,T,P[i],0);
        insert(S,1+n,k,0);
        scanf("%d%d%d",&m,&p,&Q);
        for(int i = p; i <= n; ++i) insert(S,i+n,inf,Q);
        for(int i = 1; i <= m; ++i){
            scanf("%d%d",&s,&t);
            for(int j = 1; j <= n; ++j) {
                if(j+t+n<=n*2) insert(j,j+n+t,inf,s);
            }
        }
        for(int i = 1; i <= n; ++i) insert(S,i,P[i],0);
        for(int i = 1; i < n; ++i) insert(i+n,i+n+1,inf,0);
        ans = 0;ans1 = 0;
        while(spfa()) mcf();
        if(ans1 == sum)
        cout<<ans<<endl;
        else puts("No solution");
    }
    return 0;
}
hdu5644

 

1/21:

     HDU5593 树形DP

  这是一颗固定根节点的树,要算每个点与其距离不超过k的点个数,数的办法无非向下向上数,向下数的就是基础DP,

  设定dp[i][k]表示以i为根节点向下走k步能够到达的点的个数,向上的话,由于k这么小直接暴力向上走就可以了

   这题可以分治写,待补

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
const long long INF = 1e18+1LL;
const double Pi = acos(-1.0);
const int N = 1e6+10, M = 1e3+20, mod = 1e9+7, inf = 2e9+10;

int n,k,A,B;
int dp[N][12];
vector<int > G[N];
void dfs(int u,int fa) {
    dp[u][0] = 1;
    for(int i = 0; i < G[u].size(); ++i) {
        int to = G[u][i];
        if(to == fa) continue;
        dfs(to,u);
        dp[u][1]+=1;
        for(int j = 2; j <= k; ++j)
            dp[u][j] += dp[to][j-1];
    }
}
int f[N];
int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d%d%d",&n,&k,&A,&B);
        for(int i = 1; i <= n; ++i) G[i].clear();
        memset(f,0,sizeof(f));
        f[1] = 0;
        for(int i = 2; i <= n; ++i) {
            f[i] = (1ll*A*i%(i-1)+B)%(i-1)+1;
            G[(1ll*A*i%(i-1)+B)%(i-1)+1].push_back(i);
        }
        memset(dp,0,sizeof(dp));
        dfs(1,0);
        for(int i = 1; i <= n; ++i)
            for(int j = 1; j <= k; ++j) dp[i][j] += dp[i][j-1];
        
        for(int i = 1; i <= n; ++i) {
            int cnt = 1,tmp = i;
            while(f[tmp]&&cnt<=k) {
                dp[i][k] += (dp[f[tmp]][k-cnt]);
                if(k-cnt-1>=0) dp[i][k] -= dp[tmp][k-cnt-1];
                tmp = f[tmp];
                cnt++;
            }
        }
        int ans = 0;
        for(int i = 1; i <= n; ++i) {
            ans ^= dp[i][k];
        }
        printf("%d\n",ans);
    }
    return 0;
}
HDU5593

 1/25:

     Codeforces Round #392 (Div. 2) D、E

 2/1:

  整理树链剖分

 2/6:

  CDOJ卿学姐种美丽的花:两个树状数组维护

2/8:

  codeforces #307div.2 E.GukiZ and GukiZiana   分块+二分

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
const long long INF = 1e18+1LL;
const double Pi = acos(-1.0);
const int N = 5e6+10, M = 1e3+20, mod = 1e9+7, inf = 2e9+10;
int n,q,m,block,pos[N];
LL add[N],a[N];
pair<LL ,int > b[N];
void init() {
    for(int i = 1; i <= m; ++i) {
        for(int j = (i-1)*block+1; j <= min(n,i*block); ++j)
            b[j] = MP(a[j],j);
        sort(b+(i-1)*block+1, b + min(n,i*block) + 1);
    }
}

void update(int l,int r,int c) {
    if(pos[l] == pos[r]) {
                for(int i = l; i <= r; ++i) a[i] += c;
                for(int i = block*(pos[l]-1)+1; i <= min(pos[l]*block,n); ++i) b[i] = MP(a[i],i);
                sort(b+block*(pos[l]-1)+1,b+min(pos[l]*block,n)+1);
        } else {
                for(int i = pos[l]+1; i <= (pos[r]-1); ++i) add[i]+=c;

                for(int i = l; i <= pos[l]*block; ++i) a[i] += c;
                for(int i = block*(pos[l]-1)+1; i <= pos[l]*block; ++i) b[i] = MP(a[i],i);
                sort(b+block*(pos[l]-1)+1,b+pos[l]*block+1);

                for(int i = (pos[r]-1)*block+1; i <= r; ++i) a[i] += c;
                for(int i = block*(pos[r]-1)+1; i <= min(pos[r]*block,n); ++i) b[i] = MP(a[i],i);
                sort(b+block*(pos[r]-1)+1,b+min(pos[r]*block,n)+1);
        }
}
int query(LL x) {
    int mi = inf, mx = -1;
    for(int i = 1; i <= m; ++i) {
        int pos1 = lower_bound(b+(i-1)*block+1,b+min(n,i*block)+1,make_pair(x-add[i],-1)) - b;
        int pos2 = lower_bound(b+(i-1)*block+1,b+min(n,i*block)+1,MP(x-add[i]+1,-1)) - b;
        if(b[pos1].first == x-add[i] && pos1 != min(n,i*block)+1)
        {
            mi =  min(b[pos1].second,mi);
            mx = max(b[pos1].second,mx);
        }
        if(b[pos2-1].first == x-add[i]&& pos2 != (i-1)*block+1) {
            mi =  min(b[pos2-1].second,mi);
            mx = max(b[pos2-1].second,mx);
        }
    }
    if(mx == -1 || mi == inf) return -1;
    else return mx - mi;
}
int main() {
    scanf("%d%d",&n,&q);
    block = (int) sqrt(n);
    if(n%block) m = n/block+1;else m = n/block;
    for(int i = 1; i <= n; ++i) scanf("%I64d",&a[i]),pos[i] = (i-1)/block+1;
    init();

    while(q--) {
        int op,l,r;
        LL c;
        scanf("%d",&op);
        if(op == 1) {
            scanf("%d%d%I64d",&l,&r,&c);
            update(l,r,c);
        } else {
            LL x;
            scanf("%I64d",&x);
            cout<<query(x)<<endl;
        }
    }
   // for(int i = 1; i <= n; ++i) cout<<b[i].first<<" ";cout<<endl;
    return 0;
}

/*
8 5
1 1 1 2 1 3 1 1
2 1
1 1 8 1
2 2
1 2 5 2
2 4
*/
View Code

 

 

posted @ 2017-01-12 14:44  meekyan  阅读(200)  评论(0编辑  收藏  举报