享受爆零的快感php
老叶原本是让初三的打的,而后我SB的去凑热闹了html
TM的T2写炸了(去你妹的优化),T1连-1的分都忘记判了,T3理所固然的不会数组
光荣革命啊!优化
思惟图论题,CHJ dalao给出了正解但-1输成0了缅怀spa
并且这题不能用读优玄学code
思路也很新奇,先跑一遍MST,判断是否有无解的状况htm
而后看一下MST中与1相连的边有几条get
若是小于k那么咱们把全部与1相连的边减上一个值使它们优先被选,而后跑MSTstring
大于k就加上去便可it
注意到这个值能够二分,所以不停作MST便可
CODE
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=5005,M=100005; const double EPS=1e-5; struct data { int l,r,s; double add; }a[M]; int n,m,k,cnt,father[N],tot; long long ans; inline bool comp(data a,data b) { return a.s+a.add<b.s+b.add; } inline int getfather(int k) { return father[k]==k?k:father[k]=getfather(father[k]); } inline int MST(double x) { register int i; int res=0,tot=0; for (i=1;i<=m;++i) if (a[i].l==1||a[i].r==1) a[i].add=x; sort(a+1,a+m+1,comp); for (i=1;i<=n;++i) father[i]=i; ans=0; for (i=1;i<=m;++i) { int fx=getfather(a[i].l),fy=getfather(a[i].r); if (fx!=fy) { if (a[i].l==1||a[i].r==1) ++res; ans+=a[i].s; ++tot; father[fx]=fy; } } if (tot!=n-1) return -1; return res; } int main() { freopen("path.in","r",stdin); freopen("path.out","w",stdout); register int i; scanf("%d%d%d",&n,&m,&k); for (i=1;i<=m;++i) { scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].s); if (a[i].l==1||a[i].r==1) ++tot; } if (tot<k||MST(0)==-1) { puts("-1"); return 0; } double l=-100000.0,r=100000.0; while (r-l>EPS) { double mid=(l+r)/2.0; int t=MST(mid); if (t==k) { printf("%lld",ans); break; } if (t>k) l=mid; else r=mid; } return 0; }
这么小的数据范围,就是套路的状压DP
只有我一我的想到记忆化搜索暴力玄学搜索么
好吧又是我ZZ了
首先发现n的范围只有15,果断状压成01串表示第几个串选或不选
然后预处理一个数组g[i][j]表示当t[i]上的字符为j时,与其它串的匹配状况(用二进制下压缩01串表示)
例如,四个串为
?a?
ab?
aa?
??b
例如
g[2]['a']=1101(与第四个,第三个,第一个串分别匹配)=13
g[1]['a']=1111=15
而后咱们设DP数组f[i][j]表示匹配到第i位时(第i位还没有匹配)全部串的匹配状况为j(二进制下的01串)时方案总数
则有f[i][j]能够转移出
f[i+1][j&g[i][ch]]+=f[i][j]('a'<=ch<='z')
由于这里只要一个位置不匹配那就整个串都不匹配,所以只有两边都是1才知足要求
最后ans+=全部j的1的个数刚好为k个的f[len+1][j]
C++没有以字符为下标的数组,所以全部字符减去'a'便可
CODE
#include<cstdio> #include<cstring> using namespace std; const int N=20,D=50,mod=1000003; int g[D+5][30],f[D+5][(1<<N+1)+5],n,k,ans,t; char s[N][55],ch; inline int count(int x) { int tot=0; while (x) tot+=x&1,x>>=1; return tot; } int main() { freopen("question.in","r",stdin); freopen("question.out","w",stdout); register int i,j; scanf("%d",&t); while (t--) { memset(f,0,sizeof(f)); memset(g,0,sizeof(g)); scanf("%d%d",&n,&k); for (i=1;i<=n;++i) scanf("%s",s[i]+1); int len=strlen(s[1]+1); for (i=1;i<=len;++i) for (ch='a';ch<='z';++ch) for (j=1;j<=n;++j) if (s[j][i]=='?'||ch==s[j][i]) g[i][ch-'a']|=1<<j-1; f[1][(1<<n)-1]=1; ans=0; for (i=1;i<=len;++i) for (j=0;j<1<<n;++j) if (f[i][j]) for (ch='a';ch<='z';++ch) f[i+1][j&g[i][ch-'a']]=(f[i+1][j&g[i][ch-'a']]+f[i][j])%mod; for (i=0;i<1<<n;++i) if (count(i)==k) ans=(ans+f[len+1][i])%mod; printf("%d\n",ans); } return 0; }
这就是传说中的神题么
暴力的想法都是有的,可是就是刚不出来(只有YZC dalao拿了2分)
标算是DP+KMP+矩阵乘法(快速幂),仍是不可食用的