TopCoder SRM625 DIV1

250 排列组合 数学题

统计每一个单词的数量,利用回文的特点,每次只考虑回文的左半部分,因此将之前统计的每一个字符数除以2之后进行排列组合的计算即可。需要注意的是其中字符数量为奇数的最多不超过一个。

// BEGIN CUT HERE

// END CUT HERE
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <ctime>
#include <utility>
#include <iterator>

using namespace std;

typedef long long ll;

#define clr(x,a) memset(x,a,sizeof(x))
#define sz(x) (int)x.size()
#define pb push_back
#define mp make_pair
#define REP(i,n) for(i=0;i<(n);++i)
#define FOR(i,l,h) for(i=(l);i<=(h);++i)
#define FORD(i,h,l) for(i=(h);i>=(l);--i)



class PalindromePermutations
{
        public:
        double f[55];
        double palindromeProbability(string word)
        {
            int i,j,k,n;
            n=word.length();
            f[0]=1;
            FOR(i,1,n) f[i]=f[i-1]*i;
            double D=f[n],N=f[n/2];
            int odd=0;
            FOR(i,'a','z'){
                int cnt=count(word.begin(),word.end(),i);
                if(cnt%2==1)
                    odd++;
                D/=f[cnt];
                N/=f[cnt/2];
            }
            if(odd>1)
                return 0;
            return N/D;
        }

// BEGIN CUT HERE
	
// END CUT HERE

};
// BEGIN CUT HERE

// END CUT HERE

500 最小割 图论

从终点开始按照规则走遍改地图中所有的位置。发现凡是能被1*1那一面到达的格子(i,j)都与终点(ex,ey)满足约束关系。 i=ex(mod 3)j=ey(mod 3);这样我们就能找到所有1*1能够到达的格子。接着相邻的两个1*1的格子所连接的2个格子则是1*2 与 2*1的面能够直接到达的格子。为每一个1*1的格子标号接着建图。

将每一个1*1的格子拆成两点 i与 i‘ 若点i是普通的格子则连一条弧(i,i’)流量为1(去掉这个点的花费为1),如果是起点或者终点这流量为无限大。若是洞窟则为0;

对于这些1*1的格子如果是其起点这将源点s与i连一条弧(s,i)容量为无限大

对于这些1*1的格子如果是终点则将汇点与这点i连一条弧(i‘,e)容量为无限大

对于相邻的两点i与j

连两条弧(i’,j,c) (j‘,i,c)  流量c根据连接这两点的两个格子的情况有所不同。

// BEGIN CUT HERE

// END CUT HERE
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <ctime>
#include <utility>
#include <iterator>

using namespace std;

typedef long long ll;

#define clr(x,a) memset(x,a,sizeof(x))
#define sz(x) (int)x.size()
#define pb push_back
#define mp make_pair
#define REP(i,n) for(i=0;i<(n);++i)
#define FOR(i,l,h) for(i=(l);i<=(h);++i)
#define FORD(i,h,l) for(i=(h);i>=(l);--i)

#define INF 500000
#define MAXN 6000

map<pair<int,int> ,int> mpi;

struct edge{
	int to,c,next;
};

edge e[9999999];
int que[MAXN*100];
int dis[MAXN],pre[MAXN];
int head[MAXN],head2[MAXN],en;
int st,ed,maxflow;

void add(int a,int b,int c){
	e[en].to=b;
	e[en].c=c;
	e[en].next=head[a];
	head[a]=en++;
	e[en].to=a;
	e[en].c=0;
	e[en].next=head[b];
	head[b]=en++;
}

bool bfs()
{
	memset(dis,-1,sizeof(dis));
	que[0]=st,dis[st]=1;
	int t=1,f=0;
	while(f<t)
	{

		int j=que[f++];
		for(int k=head[j];k!=-1;k=e[k].next)
		{
			int i=e[k].to;
			if(dis[i]==-1 && e[k].c)
			{
				que[t++]=i;
				dis[i]=dis[j]+1;
				if(i==ed) return true;
			}
		}
	}
	return false;
}

int update()
{
	int p,flow=INF;
    for (int i=pre[ed];i!=-1;i=pre[i])
		if(e[head2[i]].c<flow) p=i,flow=e[head2[i]].c;
    for (int i=pre[ed];i!=-1;i=pre[i])
		e[head2[i]].c-=flow,e[head2[i]^1].c+=flow;
    maxflow+=flow;
    return p;
}

void dfs()
{
	memset(pre,-1,sizeof(pre));
	memcpy(head2,head,sizeof(head2));
    for(int i=st,j;i!=-1;)
    {
        int flag=false;
        for(int k=head[i];k!=-1;k=e[k].next)
          if(e[k].c && (dis[j=e[k].to]==dis[i]+1) )
          {
                pre[j]=i;
				head2[i]=k;
				i=j;
				flag=true;
                if(i==ed)
					i=update();
                if(flag)
					break;
          }
        if (!flag) dis[i]=-1,i=pre[i];
    }
}

int dinic(){
	maxflow=0;
	while(bfs())
		dfs();
	return maxflow;
}

class BlockTheBlockPuzzle
{
        public:
        int r,c;
        bool jud(int i,int j){
            if(i<r&&i>=0&&j<c&&j>=0) return true;
            return false;
        }

        int minimumHoles(vector <string> board){
            int i,j,k,n;
            int edx,edy;
            int adj[4][2]={{3,0},{0,3},{-3,0},{0,-3}};
            r=sz(board);
            c=board[0].length();
            REP(i,r)
                REP(j,c)
                    if(board[i][j]=='$')
                        edx=i,edy=j;
            k=0;
            mpi.clear();
            REP(i,r)
                REP(j,c){
                    if((i%3)!=(edx%3) || (j%3)!=(edy%3)) continue;
                    mpi[mp(i,j)]=++k;
                }
            n=k;
            st=0,ed=k*2+1;
            clr(head,-1);
            en=0;
            REP(i,r)
                REP(j,c){
                    if(mpi.count(mp(i,j))==0) continue;
                    if(board[i][j]=='H') continue;
                    if(board[i][j]=='b'){
                        add(st,mpi[mp(i,j)],INF);
                        add(mpi[mp(i,j)],n+mpi[mp(i,j)],INF);
                    } else if(board[i][j]=='$'){
                        add(n+mpi[mp(i,j)],ed,INF );
                        add(mpi[mp(i,j)],n+mpi[mp(i,j)],INF);
                    } else {
                        add(mpi[mp(i,j)],n+mpi[mp(i,j)],1);
                    }
                    REP(k,4){
                        int tx,ty,nc,dx,dy,d;
                        tx=i+adj[k][0];
                        ty=j+adj[k][1];
                        if(!jud(tx,ty)) continue;
                        if(board[tx][ty]=='H') continue;
                        nc=2;
                        dx=adj[k][0]/3;
                        dy=adj[k][1]/3;
                        FOR(d,1,2){
                            if(board[i+dx*d][j+dy*d]=='.') continue;
                            if(board[i+dx*d][j+dy*d]=='H') nc--;
                            if(board[i+dx*d][j+dy*d]=='b'){
                                nc=INF;
                                break;
                            }
                        }
                        add(n+mpi[mp(i,j)],mpi[mp(tx,ty)],nc);
                    }
                }
                int res=dinic();
                if(res>=INF) return -1;
                return res;
        }

// BEGIN CUT HERE
	
// END CUT HERE

};
// BEGIN CUT HERE

// END CUT HERE


900 DP 

首先将第一个人的位置固定在最左侧,这样的话只要将最终的结果乘以N就可以得到循环的效果。因为 ABC 与 CAB实际上的效果是相同的。

接着用DP[I][J]表示已经入座了i个人这时候有j个集合的情况数。

如果i==K则表示所有人已经入座,这个时候集合数量是j,这便意味着我们要将N-k个空余的座位放入j个间隔中(每一个至少需要有1个空余作座位),因此DP[i][j]=C(N-k-1,j-1)

其他的情况能够采取的策略有三种,分别是增加一个新的集合,合并两个旧的集合,将新的人加入到原有的集合中去。

对于增加一个新的集合的状况,我们需要注意的是不要让j超过G(限定的集合上限)  DP[i][j]+=DP[i+1,j+1]*j   

当合并两个集合时,需要j〉=2   DP[i][j]+=DP[i+1][j-1]*j

当添加一个集合的时候需分情况讨论,到人数等于座位数,且i==N-1的时候加入的位置固定 DP[i][j]+=DP[i+1][j]

其他情况是因为分别可以加在左侧和右侧,所以要乘以2 ,并且有j个集合可以加入  DP[i][j]+=DP[i][j]*j*2


// BEGIN CUT HERE

// END CUT HERE
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <ctime>
#include <utility>
#include <iterator>

using namespace std;

typedef long long ll;

#define clr(x,a) memset(x,a,sizeof(x))
#define sz(x) (int)x.size()
#define pb push_back
#define mp make_pair
#define REP(i,n) for(i=0;i<(n);++i)
#define FOR(i,l,h) for(i=(l);i<=(h);++i)
#define FORD(i,h,l) for(i=(h);i>=(l);--i)

const ll mod=1000000007;
int C[2015][2015];
ll dp[2015][2015];

class Seatfriends
{
        public:
        int N,K,G;
        void init(int n){
            int i,j,k;
            clr(C,0);
            C[0][0]=1;
            C[1][0]=C[1][1]=1;
            FOR(i,1,n){
                C[i][0]=1;
                FOR(j,1,i)
                    C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
            }
        }

        int c(int i,int j){
            if(i==0)
                return j!=1?0:1;
            return C[i-1][j-1];
        }

        ll dfs(int k,int g){
            if(dp[k][g]!=-1) return dp[k][g];
            if(N-k<g && g>=2) return 0;
            if(k==K) return dp[k][g]=c(N-k,g);
            dp[k][g]=0;
            if(g<G)
                dp[k][g]=(dp[k][g]+dfs(k+1,g+1)*g%mod)%mod;
            if(g==1&&k==N-1&&K==N)
                dp[k][g]=(dp[k][g]+dfs(k+1,g))%mod;
            else
                dp[k][g]=(dp[k][g]+dfs(k+1,g)*2%mod*g%mod)%mod;
            if(g>=2)
                dp[k][g]=(dp[k][g]+dfs(k+1,g-1)*g%mod)%mod;
            return dp[k][g]%mod;
        }

        int countseatnumb(int N, int K, int G)
        {
            int i,j,k;
            this->N=N;
            this->K=K;
            this->G=G;
            init(N+5);
            clr(dp,-1);
            return (dfs(1,1)*N%mod);
        }

// BEGIN CUT HERE

	

// END CUT HERE

};
// BEGIN CUT HERE

// END CUT HERE


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值