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