转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
在HFUT周赛的时候做的。
A:水题嘛,多条链,枚举链的头部,也就是入度为0,出度为1的,然后遍历链求最小值。
B:水题嘛,给出m组人,每一组有ai个人,其中本人在第h组,现在在组一个队有n人(肯定包括本人),至少有一个人和自己是在同一组的概率。
也就是要取n-1个人,第h组中还有a个人,那么剩下的m-1其实本质一样,假设有b个人。
题意就是说从a+b个中取n-1个人,至少有一个人是a个人中的概率为多少。
考虑没有一个人和本人一组,便是C(b,n-1)/C(a+b,n-1) ,那么结果就是1-C(b,n-1)/C(a+b,n-1)
开始姿势不够优越,遇到了点精度问题,注意小优化一下再搞。
C:n个位置,有m种关系,表示坐在ai上的人的标号要比坐在bi上的人的标号小。给出满足限制的第y-2000个字典序排列的安排。(艹,你这也算翻译题意。。。)
由于是按字典序排的,那么我们从高位开始枚举,逐位确定。例如,我们要求第k个字典序安排,第一步假设第一个位置做的是1号人物。那么判断在这样的条件下,有c个满足条件的安排。如果c<k那么继续往后枚举,
如果c>k表示当前位就是1号人物,则枚举下一位。
至于对于一定的限制怎么求出有多少个满足条件的安排,显然是状态压缩DP,总共16个人,比较敏感的数字。
具体不说了,显然DP不是我的菜,我是渣渣
D:不错的题目,给出c组限制,ci,ti,表示当串中的字母ci的个数为ti的倍数的时候,该类型不会被惩罚。
一个字母可能有多个限制,至少需要满足其中一个限制就够了,每个字母都要满足。
问长度 为n的串有多少个满足条件的。
被数据范围吓尿了,当时还在想,MOD不是很大,是不是组合数用卢卡斯定理呢。
但是26个类型,n的范围是1e18,即使是n是100也做不来。。。果然放弃。
正解也很巧妙。注意题目说了所有的限制的乘积<=123。
则想到一种dp,dp[i][j]表示长度为i,状态为j的个数。那么这个状态怎么表示呢。
对于每一个限制,我们记录当前字母的个数mod 限制 ti 的值。
显然有sigma(ti)种情况,如果当前表示某种限制的数字为0,则说明mod ti==0,说明是ti的倍数,也就是满足条件。
(艹,这也算题解???自己都看不懂)
还是举个例子吧
如果
A 2
B 3
C 2
那么我们用0-11表示所有状态
状态 A的个数 B的个数 C的个数
0 0%2 =0 (0/2)%3=0 (0/2/3)%2=0;
1 1%2 =1 (1/2)%3=0 (1/2/3)%2=0;
2 2%2 =0 (2/2)%3=1 (2/2/3)%2=0;
3 3%2 =1 (3/2)%3=1 (3/2/3)%2=0;
4 4%2 =0 (4/2)%3=2 (4/2/3)%2=0;
5 5%2 =1 (5/2)%3=2 (5/2/3)%2=0;
6 6%2 =0 (6/2)%3=0 (6/2/3)%2=1;
7 7%2 =1 (7/2)%3=0 (7/2/3)%2=1;
8 8%2 =0 (8/2)%3=1 (8/2/3)%2=1;
9 9%2 =1 (9/2)%3=1 (9/2/3)%2=1;
10 10%2 =0 (10/2)%3=2 (10/2/3)%2=1;
11 11%2 =1 (11/2)%3=2 (11/2/3)%2=1;
然后对于某一个状态,像以下这样拆开,进行状态转移,得到新的状态,用矩阵记录一下,n很大,只 能矩阵快速幂
感谢 zz1215的指导
#include<iostream> #include<cstdio> #include<map> #include<cstring> #include<cmath> #include<vector> #include<algorithm> #include<set> #include<string> #include<queue> #define inf 100000005 #define M 200005 #define N 125 #define maxn 300005 #define eps 1e-10 #define zero(a) fabs(a)<eps #define Min(a,b) ((a)<(b)?(a):(b)) #define Max(a,b) ((a)>(b)?(a):(b)) #define pb(a) push_back(a) #define mp(a,b) make_pair(a,b) #define mem(a,b) memset(a,b,sizeof(a)) #define LL long long #define MOD 12345 #define lson step<<1 #define rson step<<1|1 #define sqr(a) ((a)*(a)) #define Key_value ch[ch[root][1]][0] //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; struct Matrix{ int m[N][N]; Matrix(){mem(m,0);} }Init,Ret; Matrix mul(Matrix a,Matrix b,int n){ Matrix ans; for(int i=0;i<n;i++) for(int j=0;j<n;j++) for(int k=0;k<n;k++) ans.m[i][j]=(ans.m[i][j]+a.m[i][k]*b.m[k][j])%MOD; return ans; } Matrix PowMod(Matrix a,LL m,int n){ Matrix ans; for(int i=0;i<n;i++) ans.m[i][i]=1; while(m){ if(m&1) ans=mul(ans,a,n); a=mul(a,a,n); m/=2; } return ans; } void Debug(Matrix a,int n){ for(int i=0;i<n;i++){ for(int j=0;j<n;j++) printf("%d ",a.m[i][j]); printf("\n"); } } LL n; int c,flag[26],cnt,val[1005],id[1005]; void Bulid(){ mem(Init.m,0); //枚举状态 for(int i=0;i<cnt;i++){ int mod[c],tmp=i; //分解 for(int j=0;j<c;j++){ mod[j]=tmp%val[j]; tmp/=val[j]; } for(int j=0;j<26;j++){ if(flag[j]){ //状态转移,相应的字母+1 for(int k=0;k<c;k++){ if(id[k]==j){ mod[k]++; if(mod[k]>=val[k]) mod[k]-=val[k]; } } int now=0; //得到新的状态 for(int k=c-1;k>=0;k--) now=now*val[k]+mod[k]; Init.m[i][now]++; //恢复现场 for(int k=0;k<c;k++){ if(id[k]==j){ mod[k]--; if(mod[k]<0) mod[k]+=val[k]; } } } } } for(int i=0;i<cnt;i++) for(int j=0;j<cnt;j++) Init.m[i][j]%=MOD; } //判断状态k满足条件,每种字母的条件至少满足一个 bool check(int k){ bool ok[26];mem(ok,false); for(int i=0;i<c;i++){ int tmp=k%val[i]; k/=val[i]; if(tmp==0) ok[id[i]]=true; } for(int i=0;i<26;i++) if(flag[i]&&!ok[i]) return false; return true; } char str[10]; int main(){ while(scanf("%I64d%d",&n,&c)!=EOF){ cnt=1;mem(flag,0); for(int i=0;i<c;i++){ scanf("%s%d",str,&val[i]); id[i]=str[0]-'A'; cnt*=val[i]; flag[id[i]]=1; } Bulid(); //Debug(Init,cnt); Ret=PowMod(Init,n,cnt); //Debug(Ret,cnt); int ans=0; for(int i=0;i<cnt;i++){ if(check(i)) ans+=Ret.m[0][i]; } printf("%d\n",ans%MOD); } return 0; }