沙茶博主终于整完了知识点并学完了早该在NOIP之前学的知识们
于是终于开始见题了,之前那个奇怪的题单的结果就是这个了
题目按沙茶博主的做题顺序排序
个人感觉(暂时)意义不大的已被自动忽略
洛谷 4917 天守阁的地板
套路(?)反演题,看反演总结
洛谷 4233 射命丸文的笔记
这题好的 orz oscar
推式子+多项式求逆
看那个省选前的多项式总结
洛谷 4918 信仰收集
据说是个套路题,wsl
奇怪的拓扑排序
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=300005,K=55; 6 int n,m,k,f,b,ma,mb,ca,cb,t1,t2,cnt,ans; 7 int p[N],noww[N],goal[N],val[N],deg[N],dp[N][K],que[N]; 8 void Maxi(int &x,int y) 9 { 10 if(x<y) x=y; 11 } 12 void Link(int f,int t) 13 { 14 noww[++cnt]=p[f],p[f]=cnt; 15 goal[cnt]=t,deg[t]++; 16 } 17 int main() 18 { 19 scanf("%d%d%d",&k,&n,&m); 20 scanf("%d%d%d%d",&ma,&mb,&ca,&cb); 21 for(int i=1;i<=k;i++) scanf("%d%d",&t1,&t2),val[t1]+=t2; 22 for(int i=1;i<=m;i++) scanf("%d%d",&t1,&t2),Link(t1,t2); 23 memset(dp,0xc0,sizeof dp); 24 dp[1][0]=val[1],que[f=b=0]=1; 25 for(int i=2;i<=n;i++) if(!deg[i]) que[++b]=i; 26 while(f<=b) 27 { 28 int tn=que[f++]; 29 for(int i=p[tn],g;i;i=noww[i]) 30 { 31 if(!(--deg[g=goal[i]])) que[++b]=g; 32 Maxi(dp[g][0],dp[tn][ma-1]-ca+val[g]); 33 Maxi(dp[g][0],dp[tn][mb-1]-cb+val[g]); 34 for(int j=1;j<mb;j++) Maxi(dp[g][j],dp[tn][j-1]); 35 } 36 } 37 for(int i=1;i<=n;i++) Maxi(ans,dp[i][0]); 38 printf("%d",ans); 39 return 0; 40 }
洛谷 3921 小学数学题
感觉只会2^(2n)+剪枝,咕咕咕
SHOI2016 黑暗前的幻想乡
矩阵树定理+容斥,没啥可说的=。=
1 #include<cstdio> 2 #include<vector> 3 #include<cstring> 4 #include<algorithm> 5 #define vpii vector<pair<int,int> > 6 #define vpit vector<pair<int,int> > ::iterator 7 using namespace std; 8 const int N=20,mod=1e9+7; 9 int n,m,t1,t2,all,ans,tmp,deg[N],mat[N][N]; vpii ve[N]; 10 void Add(int &x,int y) 11 { 12 x+=y; 13 if(x>=mod) x-=mod; 14 } 15 int Bitcount(int x) 16 { 17 int ret=0; 18 while(x) 19 ret++,x-=x&-x; 20 return ret; 21 } 22 void exGCD(int a,int b,int &x,int &y) 23 { 24 if(!b) x=1,y=0; 25 else exGCD(b,a%b,y,x),y-=a/b*x; 26 } 27 int Inv(int x) 28 { 29 int xx,yy; 30 exGCD(x,mod,xx,yy); 31 return (xx%mod+mod)%mod; 32 } 33 void Guass() 34 { 35 for(int i=1;i<n;i++) 36 for(int j=1;j<n;j++) 37 if(i!=j) 38 { 39 int tmp=1ll*mat[j][i]*Inv(mat[i][i])%mod; 40 for(int k=i;k<=n;k++) 41 Add(mat[j][k],mod-1ll*tmp*mat[i][k]%mod); 42 } 43 } 44 int main() 45 { 46 scanf("%d",&n),all=(1<<(n-1))-1; 47 for(int i=1;i<n;i++) 48 { 49 scanf("%d",&m); 50 for(int j=1;j<=m;j++) 51 { 52 scanf("%d%d",&t1,&t2); 53 ve[i].push_back(make_pair(t1,t2)); 54 } 55 } 56 for(int i=1;i<=all;i++) 57 { 58 int tmp=1; 59 memset(deg,0,sizeof deg); 60 memset(mat,0,sizeof mat); 61 for(int j=1;j<=n;j++) 62 if(i&(1<<(j-1))) 63 for(vpit it=ve[j].begin();it!=ve[j].end();it++) 64 { 65 int x=it->first,y=it->second; 66 Add(mat[x][y],mod-1),Add(mat[y][x],mod-1),deg[x]++,deg[y]++; 67 } 68 for(int j=1;j<=n;j++) mat[j][j]+=deg[j]; Guass(); 69 for(int j=1;j<n;j++) tmp=1ll*tmp*mat[j][j]%mod; 70 if((n-1-Bitcount(i))&1) Add(ans,mod-tmp); else Add(ans,tmp); 71 } 72 printf("%d",ans); 73 return 0; 74 }
ZJOI2015 地震后的幻想乡
神题,orz CLJ
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int M=55,S=(1<<10)+10; 6 int n,m,t1,t2,all,bit[S],edg[S]; 7 long long C[M][M],unc[S][M],con[S][M]; 8 void Pre() 9 { 10 all=(1<<n)-1; 11 for(int i=0;i<=m;i++) C[i][0]=1; 12 for(int i=1;i<=m;i++) 13 for(int j=1;j<=i;j++) 14 C[i][j]=C[i-1][j-1]+C[i-1][j]; 15 for(int i=1;i<=all;i++) bit[i]=bit[i>>1]+(i&1); 16 } 17 int main() 18 { 19 scanf("%d%d",&n,&m),Pre(); 20 for(int i=1;i<=m;i++) 21 { 22 scanf("%d%d",&t1,&t2); 23 int s=(1<<(t1-1))|(1<<(t2-1)); 24 for(int j=0;j<=all;j++) 25 if((j&s)==s) edg[j]++; 26 } 27 for(int i=0;i<=all;i++) 28 if(bit[i]==1) con[i][0]=1; 29 else 30 { 31 int lbt=i&-i; 32 for(int j=i&(i-1);j;j=(j-1)&i) 33 if(j&lbt) 34 for(int k=0;k<=edg[j];k++) 35 for(int h=0;h<=edg[i^j];h++) 36 unc[i][k+h]+=con[j][k]*C[edg[i^j]][h]; 37 for(int j=0;j<=edg[i];j++) 38 con[i][j]=C[edg[i]][j]-unc[i][j]; 39 } 40 double ans=0; 41 for(int i=0;i<=m;i++) 42 ans+=(1.0*unc[all][i])/(1.0*C[m][i]); 43 printf("%.6f",ans/(1.0*(m+1))); 44 return 0; 45 }
ZOJ3522 Hide and seek
YJC -> 秒切人
用LCT把两个端点连成的链提出来(边权转为点权处理),当然我们只需要分别考虑两个点,这里就都按照从下往上走考虑
可以发现如果距离变短了一定是链上一个点下面的都变短了,用LCT维护子树大小(为了维护这个还要要先DFS一遍记录原子树的大小来维护虚儿子的大小),点权和(也就是边权和)每个点上面的下去/下面的上来的距离和(都维护,因为Turnroot的时候会翻转左右子树),这样找到这个分界点就能求答案了。找分解点时把它Splay上去在Splay上面二分走就可以了
1 #pragma GCC optimize(2) 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define lli long long 6 using namespace std; 7 const int N=200005; 8 int fth[N],son[N][2],rev[N],stk[N]; 9 int p[N],noww[N],goal[N]; 10 int siz[N],vir[N],val[N]; 11 lli sum[N],ups[N],dws[N]; 12 int n,m,t1,t2,t3,cnt,top; 13 14 void Clean() 15 { 16 memset(p,cnt=0,sizeof p); 17 memset(ups,0,sizeof ups); 18 memset(dws,0,sizeof dws); 19 memset(fth,0,sizeof fth); 20 memset(son,0,sizeof son); 21 memset(rev,0,sizeof rev); 22 memset(sum,0,sizeof sum); 23 memset(vir,0,sizeof vir); 24 memset(val,0,sizeof val); 25 memset(siz,0,sizeof siz); 26 } 27 28 void Link(int f,int t) 29 { 30 noww[++cnt]=p[f]; 31 goal[cnt]=t,p[f]=cnt; 32 noww[++cnt]=p[t]; 33 goal[cnt]=f,p[t]=cnt; 34 } 35 void DFS(int nde,int far) 36 { 37 fth[nde]=far; 38 for(int i=p[nde];i;i=noww[i]) 39 if(goal[i]!=far) 40 { 41 DFS(goal[i],nde); 42 siz[nde]+=siz[goal[i]]; 43 } 44 vir[nde]=siz[nde]; 45 } 46 47 bool Nottop(int nde) 48 { 49 int fa=fth[nde]; 50 return son[fa][0]==nde||son[fa][1]==nde; 51 } 52 void Release(int nde) 53 { 54 if(rev[nde]) 55 { 56 int &lson=son[nde][0],&rson=son[nde][1]; 57 rev[nde]^=1,rev[lson]^=1,rev[rson]^=1; 58 swap(ups[nde],dws[nde]),swap(lson,rson); 59 } 60 } 61 void Pushup(int nde) 62 { 63 int lson=son[nde][0],rson=son[nde][1]; 64 Release(nde),Release(lson),Release(rson); 65 sum[nde]=sum[lson]+sum[rson]+val[nde]; 66 siz[nde]=siz[lson]+siz[rson]+vir[nde]; 67 ups[nde]=ups[lson]+ups[rson]+(sum[lson]+val[nde])*siz[rson]+sum[lson]*vir[nde]; 68 dws[nde]=dws[lson]+dws[rson]+(sum[rson]+val[nde])*siz[lson]+sum[rson]*vir[nde]; 69 } 70 void Rotate(int nde) 71 { 72 int fa=fth[nde],gr=fth[fa],isl=nde==son[fa][0]; 73 if(Nottop(fa)) son[gr][fa==gr[son][1]]=nde; 74 fth[nde]=gr,fth[fa]=nde,fth[son[nde][isl]]=fa; 75 son[fa][isl^1]=son[nde][isl],son[nde][isl]=fa; 76 Pushup(fa),Pushup(nde); 77 } 78 void Splay(int nde) 79 { 80 stk[top=1]=nde; 81 for(int i=nde;Nottop(i);i=fth[i]) 82 stk[++top]=fth[i]; 83 while(top) Release(stk[top--]); 84 while(Nottop(nde)) 85 { 86 int fa=fth[nde],gr=fth[fa]; 87 if(Nottop(fa)) 88 Rotate(((son[fa][0]==nde)==(son[gr][0]==fa))?fa:nde); 89 Rotate(nde); 90 } 91 Pushup(nde); 92 } 93 void Access(int nde) 94 { 95 int mem=nde,lst=0; 96 while(nde) 97 { 98 Splay(nde); 99 vir[nde]+=siz[son[nde][1]]-siz[lst]; 100 son[nde][1]=lst,Pushup(nde); 101 lst=nde,nde=fth[nde]; 102 } 103 Splay(mem); 104 } 105 void Turnroot(int nde) 106 { 107 Access(nde),rev[nde]^=1; 108 } 109 void Split(int x,int y) 110 { 111 Turnroot(x),Access(y); 112 } 113 int Findb(int x,int v) 114 { 115 int ret=-1,nde=x; 116 while(nde) 117 { 118 Release(nde); 119 if((val[nde]+sum[son[nde][0]])*2<=sum[x]+v) 120 v-=(val[nde]+sum[son[nde][0]])*2,ret=nde,nde=son[nde][1]; 121 else 122 nde=son[nde][0]; 123 } 124 return ret; 125 } 126 lli Query(int x,int y,int v) 127 { 128 if(x!=y) 129 { 130 Split(x,y); 131 if(sum[y]<=v) return 0; 132 int brd=Findb(y,v); 133 if(brd==-1) return 0; else Splay(brd); 134 return (sum[brd]-v)*siz[son[brd][1]]-dws[son[brd][1]]*2; 135 } 136 else return 0; 137 } 138 139 int main() 140 { 141 while(scanf("%d",&n)!=EOF) 142 { 143 Clean(); 144 for(int i=1;i<n;i++) 145 { 146 scanf("%d%d%d",&t1,&t2,&t3); 147 Link(t1,i+n),Link(i+n,t2); 148 val[i+n]=sum[i+n]=t3; 149 } 150 for(int i=1;i<=n;i++) val[i]=0,siz[i]=1; DFS(1,0); 151 scanf("%d",&m); 152 for(int i=1;i<=m;i++) 153 { 154 scanf("%d%d%d",&t1,&t2,&t3); 155 printf("%lld ",Query(t1,t2,t3)+Query(t2,t1,t3)); 156 } 157 } 158 return 0; 159 }
ZOJ3229 Shoot the Bullet
纯粹复习网络流用的,没啥可看的
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=1500,M=80000,inf=1e9; 6 int p[N],pp[N],noww[M],goal[M],flow[M]; 7 int dep[N],que[N],ins[N],ots[N],low[M],anss[M]; 8 int n,m,s,t,f,b,ss,tt,rd,id,ll,rr,tar,lim,cnt,ans,num; 9 void Link(int f,int t,int v) 10 { 11 noww[++cnt]=p[f],p[f]=cnt; 12 goal[cnt]=t,flow[cnt]=v; 13 noww[++cnt]=p[t],p[t]=cnt; 14 goal[cnt]=f,flow[cnt]=0; 15 } 16 void Init() 17 { 18 s=n+m+1,t=s+1,ss=t+1,tt=ss+1,ans=-inf,num=0; 19 memset(p,0,sizeof p),cnt=1; 20 memset(ins,0,sizeof ins); 21 memset(ots,0,sizeof ots); 22 } 23 bool Lay(int st,int ed) 24 { 25 for(int i=1;i<=ed;i++) pp[i]=p[i]; 26 memset(dep,-1,sizeof dep); 27 que[f=b=0]=st,dep[st]=0; 28 while(f<=b) 29 { 30 int tn=que[f++]; 31 for(int i=pp[tn],g;i;i=noww[i]) 32 if(flow[i]&&dep[g=goal[i]]==-1) 33 dep[g]=dep[tn]+1,que[++b]=g; 34 } 35 return ~dep[ed]; 36 } 37 int Aug(int nd,int ed,int mn) 38 { 39 if(nd==ed||!mn) return mn; 40 int tmp=0,tep; 41 for(int i=pp[nd],g;i;i=noww[i]) 42 { 43 pp[nd]=i; 44 if(dep[g=goal[i]]==dep[nd]+1) 45 if((tep=Aug(g,ed,min(flow[i],mn)))) 46 { 47 flow[i]-=tep,mn-=tep; 48 flow[i^1]+=tep,tmp+=tep; 49 if(!mn) break; 50 } 51 } 52 return tmp; 53 } 54 bool Able() 55 { 56 for(int i=p[ss];i;i=noww[i]) 57 if(flow[i]) return false; 58 return true; 59 } 60 int main() 61 { 62 while(scanf("%d%d",&n,&m)!=EOF) 63 { 64 Init(),Link(t,s,inf); 65 for(int i=1;i<=m;i++) 66 { 67 scanf("%d",&rd),Link(i+n,t,inf); 68 ots[i+n]+=rd,ins[t]+=rd; 69 } 70 for(int i=1;i<=n;i++) 71 { 72 scanf("%d%d",&tar,&lim),Link(s,i,lim); 73 for(int j=1;j<=tar;j++) 74 { 75 scanf("%d%d%d",&id,&ll,&rr),id++; 76 Link(i,id+n,rr-ll),low[++num]=ll; 77 ots[i]+=ll,ins[id+n]+=ll,anss[num]=cnt; 78 } 79 } 80 for(int i=1;i<=t;i++) 81 if(ins[i]-ots[i]<0) Link(i,tt,ots[i]-ins[i]); 82 else Link(ss,i,ins[i]-ots[i]); 83 while(Lay(ss,tt)) Aug(ss,tt,inf); 84 if(Able()) 85 { 86 p[ss]=p[tt]=p[t]=0; 87 while(Lay(s,t)) Aug(s,t,inf); 88 for(int i=p[s];i;i=noww[i]) ans+=flow[i^1]; 89 printf("%d ",ans); 90 for(int i=1;i<=num;i++) 91 printf("%d ",low[i]+flow[anss[i]]); 92 } 93 else puts("-1"); puts(""); 94 } 95 return 0; 96 }
HNOI2015 接水果
DFS序之后变成二维第k大
YJC搞了一个log^3的算法,先DSU on tree+线段树合并把链从一边整合到另一边,然后变成区间第k大
或者好像可以树套树/整体二分+扫描线
这题太tm僵硬了,要是将来有机会再写吧。。。
(你没机会了
COGS2198 帕秋莉的超级多项式
如果我省选没退役,我一定要写一个多项式全家桶.jpg
(你没机会了++
BZOJ 4166-4168
只有第一个可做,因为第二个是没意义的乱搞题,第三个是真·难题
(现在才发现这位奆奆已经过滤了一遍沙茶题和不可做题了(orz),结果我这个沙茶又看了一遍)
月宫的符卡序列
因为不会回文树,于是从这题直接学习回文树的哈希建法,是不是科技点歪了啊。。。
学manacher的时候应该说过本质不同的回文串的数目只有$O(n)$级别
于是朴素的想法当然是把每个回文串都算一遍
优化一下就是我们先算最长的,然后算被它包含的(其实这样形成的这个树形结构就是回文树)
用哈希搞一搞,叶子的权值单独算,非叶子节点的值就是所有儿子的异或和
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<tr1/unordered_map> 5 #define lli long long 6 #define umap unordered_map 7 using namespace std; 8 using namespace std::tr1; 9 const int mod1=1e9+7,mod2=2147483647; 10 const int bas1=131,bas2=233,N=1e6+60; 11 char str[N],man[N<<1]; 12 int r[N<<1],dp[N],fth[N]; 13 int pw1[N],pw2[N],hsh1[N],hsh2[N]; 14 int T,n,tot,len,mar,mid,ans; umap<lli,int> mp; 15 void Maxi(int &x,int y){if(x<y) x=y;} 16 void Init() 17 { 18 len=strlen(str+1),n=2*len+1; 19 man[0]=')',man[n+1]='('; 20 for(int i=1;i<=n;i++) 21 man[i]=(i&1)?'?':str[i>>1]; 22 for(int i=1;i<=len;i++) 23 { 24 hsh1[i]=(1ll*hsh1[i-1]*bas1%mod1+str[i])%mod1; 25 hsh2[i]=(1ll*hsh2[i-1]*bas2%mod2+str[i])%mod2; 26 } 27 memset(r,0,sizeof r); 28 memset(dp,0,sizeof dp); 29 memset(fth,0,sizeof fth); 30 tot=mar=mid=ans=0,mp.clear(); 31 } 32 lli Ghash(int l,int r) 33 { 34 int ha1=(hsh1[r]-1ll*hsh1[l-1]*pw1[r-l+1]%mod1+mod1)%mod1; 35 int ha2=(hsh2[r]-1ll*hsh2[l-1]*pw2[r-l+1]%mod2+mod2)%mod2; 36 return ((lli)ha1<<32)+ha2; 37 } 38 int main() 39 { 40 scanf("%d",&T),pw1[0]=pw2[0]=1; 41 for(int i=1;i<=1000000;i++) 42 { 43 pw1[i]=1ll*pw1[i-1]*bas1%mod1; 44 pw2[i]=1ll*pw2[i-1]*bas2%mod2; 45 } 46 while(T--) 47 { 48 scanf("%s",str+1),Init(); 49 for(int i=1;i<=n;i++) 50 { 51 r[i]=(mar>=i)?min(mar-i+1,r[2*mid-i]):1; 52 int lst=r[i]==1?0:mp[Ghash((i-r[i])/2+1,(i+r[i]-1)/2)]; 53 while(man[i+r[i]]==man[i-r[i]]) 54 { 55 r[i]++; 56 lli hsh=Ghash((i-r[i])/2+1,(i+r[i]-1)/2); 57 if(!mp.count(hsh)) 58 { 59 mp[hsh]=++tot; 60 fth[tot]=lst,lst=tot; 61 } 62 else lst=mp[hsh]; 63 } 64 if(i+r[i]-1>mar) mar=i+r[i]-1,mid=i; 65 if(lst) dp[lst]^=i/2-1; 66 } 67 for(int i=tot;i;i--) 68 { 69 Maxi(ans,dp[i]); 70 dp[fth[i]]^=dp[i]; 71 } 72 printf("%d ",ans); 73 } 74 return 0; 75 }
BZOJ 2553 禁忌
AC自动机上DP,设$dp[i][j]$表示走了i步在点j的期望伤害,每次在AC自动机上走,走到一个禁忌的结尾就连回根节点和一个虚拟节点,虚拟节点表示可以在这里摸着
矩乘优化一下,然后就卡精度了2333
1 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define double long double 6 using namespace std; 7 const int N=105; 8 int n,alp,len,tot; char rd[N]; 9 int trie[N][26],fail[N],endp[N],que[N],vis[N]; 10 struct a 11 { 12 double mat[N][N]; 13 void Clean() 14 { 15 memset(mat,0,sizeof mat); 16 } 17 }dp; 18 a Matime(a x,a y) 19 { 20 a ret; ret.Clean(); 21 for(int i=0;i<=tot;i++) 22 for(int k=0;k<=tot;k++) 23 for(int j=0;j<=tot;j++) 24 ret.mat[i][j]+=x.mat[i][k]*y.mat[k][j]; 25 return ret; 26 } 27 a Maqpow(a x,int k) 28 { 29 if(k==1) return x; 30 a tmp=Maqpow(x,k>>1); 31 tmp=Matime(tmp,tmp); 32 if(k&1) tmp=Matime(tmp,x); 33 return tmp; 34 } 35 void Insert(char *s) 36 { 37 int len=strlen(s),nde=0; 38 for(int i=0;i<len;i++) 39 { 40 int ch=s[i]-'a'; 41 if(!trie[nde][ch]) 42 trie[nde][ch]=++tot; 43 nde=trie[nde][ch]; 44 } 45 endp[nde]=true; 46 } 47 void Create() 48 { 49 int f=0,b=-1,nde=0; 50 for(int i=0;i<alp;i++) 51 if(nde=trie[0][i]) 52 fail[nde]=0,que[++b]=nde; 53 while(f<=b) 54 { 55 int tn=que[f++]; 56 endp[tn]|=endp[fail[tn]]; 57 for(int i=0;i<alp;i++) 58 if(nde=trie[tn][i]) 59 fail[nde]=trie[fail[tn]][i],que[++b]=nde; 60 else 61 trie[tn][i]=trie[fail[tn]][i]; 62 } 63 } 64 void Getfunc() 65 { 66 int f=0,b=0,nde=0; 67 double pos=1.0/alp; 68 vis[que[0]=0]=true; 69 while(f<=b) 70 { 71 int tn=que[f++]; 72 for(int i=0;i<alp;i++) 73 { 74 if(!vis[nde=trie[tn][i]]) 75 vis[nde]=true,que[++b]=nde; 76 if(!endp[nde]) dp.mat[tn][nde]+=pos; 77 else dp.mat[tn][tot]+=pos,dp.mat[tn][0]+=pos; 78 } 79 } 80 dp.mat[tot][tot]=1; 81 } 82 int main() 83 { 84 scanf("%d%d%d",&n,&len,&alp); 85 for(int i=1;i<=n;i++) 86 scanf("%s",rd),Insert(rd); 87 Create(),tot++,Getfunc(); 88 dp=Maqpow(dp,len); 89 printf("%.7Lf",dp.mat[0][tot]); 90 return 0; 91 }
GG COGS凉了,于是暂时就这样吧
( 大 失 败 )