problem1 link
直接模拟。
import java.util.*; import java.math.*; import static java.lang.Math.*; public class Arrows { public int longestArrow(String s) { int result=-1; for(int i=0;i<s.length();++i) { final char c=s.charAt(i); if(c=='<') { int len=1; if(i+1<s.length()&&(s.charAt(i+1)=='-'||s.charAt(i+1)=='=')) { ++len; for(int k=i+2;k<s.length()&&s.charAt(k)==s.charAt(i+1);++k) { ++len; } } result=Math.max(result,len); } else if(c=='>') { int len=1; if(i-1>=0&&(s.charAt(i-1)=='-'||s.charAt(i-1)=='=')) { ++len; for(int k=i-2;k>=0&&s.charAt(k)==s.charAt(i-1);--k) { ++len; } } result=Math.max(result,len); } } return result; } }
problem2 link
把词建一个树,那么对于一个节点$u$,如果$u$不是一个单词,那么$f(u)=prod _{vin S_{u}}f(v)$,否则$f(u)=1+prod _{vin S_{u}}f(v)$.$S_{u}$表示$u$的孩子集合。
import java.util.*; import java.math.*; import static java.lang.Math.*; public class PrefixFreeSubsets { static class Tree { public boolean end; Tree[] sons=null; public Tree() { end=false; sons=new Tree[26]; } } static Tree head=null; public long cantPrefFreeSubsets(String[] words) { head=new Tree(); for(String s:words) { Tree cur=head; for(int i=0;i<s.length();++i) { int t=s.charAt(i)-'a'; if(cur.sons[t]==null) { cur.sons[t]=new Tree(); } cur=cur.sons[t]; } cur.end=true; } return dfs(head); } static long dfs(Tree cur) { long result=1,num=0; for(int i=0;i<26;++i) { if(cur.sons[i]==null) { continue; } result*=dfs(cur.sons[i]); ++num; } if(num==0) { return 2; } if(cur.end) { ++result; } return result; } }
problem3 link
设$f[i]=1$ 表示先手赢,$f[i]=0$ 表示后手赢。由于每次拿的石子数范围是$[1,22]$,所以如果出现两个位置$p,q$,使得$f[p],f[p+1],..,f[p+21]$与$f[q],f[q+1],..,f[q+21]$完全相等,那么就形成一个循环。所以只需要暴力找到这个循环位置即可。
import java.util.*; import java.math.*; import static java.lang.Math.*; public class LongLongNim { static boolean[] f=new boolean[1<<22]; static int[] g=new int[1<<22]; public int numberOfWins(int maxN,int[] moves) { Arrays.fill(f,false); Arrays.fill(g,-1); f[0]=false; int pre=0; int start0=-1,start1=-1; for(int i=1;i<=maxN;++i) { boolean ok=false; for(int j=0;j<moves.length&&i>=moves[j];++j) { if(!f[i-moves[j]]) { ok=true; break; } } f[i]=ok; if(f[i]) { pre=pre<<1|1; } else { pre=pre<<1; } if(i>22&&(pre&(1<<22))!=0) { pre^=1<<22; } if(i<22) { continue; } if(g[pre]==-1) { g[pre]=i-21; } else if(i-21-g[pre]>=22){ start0=g[pre]; start1=i-21; break; } } if(start0==-1) { int result=0; for(int i=1;i<=maxN;++i) { if(!f[i]) { ++result; } } return result; } int result0=0,result1=0; for(int i=1;i<start0;++i) { if(!f[i]) { ++result0; } } for(int i=start0;i<start1;++i) { if(!f[i]) { ++result1; } } maxN-=start0-1; result1*=maxN/(start1-start0); maxN%=start1-start0; for(int i=0;i<maxN;++i) { if(!f[start0+i]) { ++result1; } } result1+=result0; return result1; } }