【TJOI2013 Day1合集】BZOJ3170 松鼠聚会 BZOJ3171 循环格 BZOJ3172 单词
松鼠聚会:
首先题目给出的松鼠之间的距离应该是max(|x1-x2|,|y1-y2|)、、
然后我们知道、如果用x'=x+y,y'=x-y的方式重构所有点的坐标、
两个点之间的距离就变成了max(|x1'-x2'|,|y1'-y2'|)、、
于是我们用给的两个数字解一个一元二次方程得到原来的坐标、、
然后前缀和乱搞搞统计曼哈顿距离和就好了、
Code:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> #include <cstring> #include <vector> #include <set> #include <map> #include <queue> #define ps system("pause") #define message printf("*\n") #define pb push_back #define X first #define Y second #define PII pair<int,int> #define rep(a,b,c) for(int a=b;a<=c;a++) #define per(a,b,c) for(int a=b;a>=c;a--) typedef long long ll; using namespace std; struct node{ double x,y; int id; }p[100010]; bool cmp1(node a,node b){ return a.x<b.x; } bool cmp2(node a,node b){ return a.y<b.y; } double sx=0,sy=0,ts; double ans[100010]; int n; int main(){ scanf("%d",&n); rep(i,1,n){ double xx,yy; scanf("%lf%lf",&xx,&yy); p[i].x=(xx+yy)/2;p[i].y=(xx-yy)/2; sx+=p[i].x;sy+=p[i].y;p[i].id=i; } sort(p+1,p+n+1,cmp1);ts=0; rep(i,1,n){ ans[p[i].id]+=(i-1)*p[i].x-ts; ans[p[i].id]+=(sx-ts)-(n-i+1)*p[i].x; ts+=p[i].x; } sort(p+1,p+n+1,cmp2);ts=0; rep(i,1,n){ ans[p[i].id]+=(i-1)*p[i].y-ts; ans[p[i].id]+=(sy-ts)-(n-i+1)*p[i].y; ts+=p[i].y; } double s=1e18; rep(i,1,n) s=min(s,ans[i]); printf("%.0lf\n",s); return 0; }
循环格:
或许可以生成所有合法状态之后按行或者列方向做状压DP、、
但是我太弱了于是写了费用流、
图形成完美循环的充要条件是每个点的入度和出度都是1、、
于是拆点为入和出、由S向入i,T向出i分别连容量为1费用为0的边、、
对每个点入i,向相邻点的出j连容量为1的边、、
然后在最后的最大流中入i到出j如果存在流量就代表i上字母是指向j的、、
所以对原有的字母指向的边费用为0,因为不用修改、其它的就是1了、、
最后跑mincost-maxflow就好了、、
Code:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> #include <cstring> #include <vector> #include <set> #include <map> #include <queue> #define ps system("pause") #define message printf("*\n") #define pb push_back #define X first #define Y second #define PII pair<int,int> #define rep(a,b,c) for(int a=b;a<=c;a++) #define per(a,b,c) for(int a=b;a>=c;a--) typedef long long ll; using namespace std; #define inf 9999999 int l,r=2,n,m,S,T; char c[20][20]; int t[100010],w[100010],v[100010],next[100010],s[100010]; int g[2010],e[2010],d[2010],fr[2010],uc[2010],ans=0; bool ud[2010]; bool vis[1010]; int in[20][20],ou[20][20]; void addedge(int aa,int bb,int cc,int vv){ //printf("%d %d %d %d\n",aa,bb,cc,vv); t[r]=bb;w[r]=cc;v[r]=vv; if (!ud[aa]) g[aa]=e[aa]=r,ud[aa]=true; else next[e[aa]]=r,e[aa]=r; r++; t[r]=aa;w[r]=0;v[r]=-vv; if (!ud[bb]) g[bb]=e[bb]=r,ud[bb]=true; else next[e[bb]]=r,e[bb]=r; r++; } bool spfa(){ l=1;r=1;s[1]=S; memset(vis,0,sizeof vis); memset(fr,0,sizeof fr); memset(uc,0,sizeof uc); rep(i,S,T) d[i]=inf; d[S]=0;vis[S]=true; while (l<=r){ for (int u=g[s[l]];u;u=next[u]) if (w[u] && d[t[u]]>d[s[l]]+v[u]){ d[t[u]]=d[s[l]]+v[u]; fr[t[u]]=s[l];uc[t[u]]=u; if (!vis[t[u]]){ s[++r]=t[u]; vis[t[u]]=true; } } vis[s[l]]=false; l++; } return d[T]!=inf; } int argu(){ int cur=T,res=inf,flow=0; while (cur!=S){ res=min(res,w[uc[cur]]); flow+=v[uc[cur]]; cur=fr[cur]; } cur=T; while (cur!=S){ w[uc[cur]]-=res; w[uc[cur]^1]+=res; cur=fr[cur]; } return res*flow; } int main(){ scanf("%d%d\n",&n,&m); rep(i,1,n){ scanf(" "); rep(j,1,m) c[i][j]=getchar(); } rep(i,1,n) rep(j,1,m){ in[i][j]=(i-1)*m+j; ou[i][j]=in[i][j]+n*m; } S=0,T=n*m*2+1; rep(i,1,n) rep(j,1,m){ addedge(S,in[i][j],1,0); addedge(ou[i][j],T,1,0); switch (c[i][j]){ case 'L': addedge(in[i][j],ou[i][(j-1-m)%m+m],1,0); addedge(in[i][j],ou[i][j%m+1],1,1); addedge(in[i][j],ou[(i-1-n)%n+n][j],1,1); addedge(in[i][j],ou[i%n+1][j],1,1); break; case 'R': addedge(in[i][j],ou[i][(j-1-m)%m+m],1,1); addedge(in[i][j],ou[i][j%m+1],1,0); addedge(in[i][j],ou[(i-1-n)%n+n][j],1,1); addedge(in[i][j],ou[i%n+1][j],1,1); break; case 'U': addedge(in[i][j],ou[i][(j-1-m)%m+m],1,1); addedge(in[i][j],ou[i][j%m+1],1,1); addedge(in[i][j],ou[(i-1-n)%n+n][j],1,0); addedge(in[i][j],ou[i%n+1][j],1,1); break; case 'D': addedge(in[i][j],ou[i][(j-1-m)%m+m],1,1); addedge(in[i][j],ou[i][j%m+1],1,1); addedge(in[i][j],ou[(i-1-n)%n+n][j],1,1); addedge(in[i][j],ou[i%n+1][j],1,0); break; } } while (spfa()) ans+=argu(); printf("%d\n",ans); return 0; }
单词:
这题有一万种方法可以做、、弱*的LZ就用KMP水过了、、
大致还可以用SA、AC自动机、字符串HASH之类的过吧、、
Code:
var n,i,j,cur,k,p,ans:longint; s:array [0..2000010] of char; ff:array [0..2000010] of longint; st,len:array [0..201] of longint; w:array [0..201,0..100010] of char; begin readln(n); cur:=0; for i:=1 to n do begin st[i]:=cur+1;p:=0; while not eoln do begin inc(cur); read(s[cur]); inc(p); w[i][p]:=s[cur]; end; len[i]:=p; inc(cur);s[cur]:='#'; readln; end; for i:=1 to n do begin ff[1]:=0;k:=0; for j:=2 to len[i] do begin while (k>0) and (w[i][k+1]<>w[i][j]) do k:=ff[k]; if w[i][k+1]=w[i][j] then inc(k); ff[j]:=k; end; k:=0;ans:=0; for j:=1 to cur do begin while (k>0) and (w[i][k+1]<>s[j]) do k:=ff[k]; if w[i][k+1]=s[j] then inc(k); if k=len[i] then begin inc(ans); k:=ff[k]; end; end; writeln(ans); end; end.