TJOI2015 day1解题报告
博客园的编辑器真的是太蛋疼了= =,想用tex然后上jpg又贴不了链接,真的很纠结啊= =
描述:戳上面吧= =
首先这道题我觉得是这套题最漂亮的一道题了(虽然说学校的题库里居然有一道和这个一模一样的= =)
首先我们可以先把那个式子转化为其中b[i]是表示矩阵a中第i行为0或为1,然后就有两种方法转化为网络流啦
方法一:可以用最大权闭合子图的方法来考虑,将c[i]以及a[i][j]的选择与否视为事件的话,可以发现是一个点数为n*n的最大权闭合子图,就可以愉快的用网络流来搞辣
方法二:我们可以看做一个二元关系,因为可以看做i的选取会花费 c[i],而同时选择i, j则会获得一定的收益,那么我们可以得到一个二元关系(但还是需要经过一定的转化的),然后点数就只有n啦
我只写了方法一,虽说点数很多,但边数少,还是很快的
还有一种水法,貌似直接把所有a相加然后减去b就行辣(数据就是这么水= =)
CODE:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define maxn 300000 7 #define maxm 900000 8 struct edges{ 9 int to,next,cap; 10 }edge[maxm*2]; 11 int next[maxn],l; 12 inline void addedge(int x,int y,int z) { 13 l++; 14 edge[l*2]=(edges){y,next[x],z};next[x]=l*2; 15 edge[l*2+1]=(edges){x,next[y],0};next[y]=l*2+1; 16 } 17 #define inf 0x7fffffff 18 int s,t,h[maxn],p[maxn],gap[maxn]; 19 int sap(int u,int flow) { 20 if (u==t) return flow; 21 int cnt=0; 22 for (int i=p[u];i;i=edge[i].next) 23 if (edge[i].cap&&h[u]==h[edge[i].to]+1) { 24 int cur=sap(edge[i].to,min(flow-cnt,edge[i].cap)); 25 edge[i].cap-=cur;edge[i^1].cap+=cur; 26 p[u]=i; 27 if ((cnt+=cur)==flow) return cnt; 28 } 29 if (!(--gap[h[u]])) h[s]=t; 30 gap[++h[u]]++; 31 p[u]=next[u]; 32 return cnt; 33 } 34 inline int maxflow(){ 35 for (int i=1;i<=t;i++) p[i]=next[i]; 36 memset(gap,0,sizeof(gap)); 37 memset(h,0,sizeof(h)); 38 gap[0]=t; 39 int flow=0; 40 while (h[s]<t) flow+=sap(s,inf); 41 return flow; 42 } 43 int id[510][510],cnt,n; 44 int main(){ 45 freopen("algebra.in","r",stdin); 46 freopen("algebra.out","w",stdout); 47 scanf("%d",&n); 48 for (int i=0;i<=n;i++) 49 for (int j=1;j<=n;j++) id[i][j]=++cnt; 50 s=++cnt,t=++cnt; 51 int sum=0; 52 for (int i=1;i<=n;i++) 53 for (int j=1;j<=n;j++) { 54 int x; 55 scanf("%d",&x); 56 addedge(s,id[i][j],x); 57 sum+=x; 58 } 59 for (int i=1;i<=n;i++) { 60 int x; 61 scanf("%d",&x); 62 addedge(id[0][i],t,x); 63 } 64 for (int i=1;i<=n;i++) 65 for (int j=1;j<=n;j++) { 66 addedge(id[i][j],id[0][i],inf); 67 addedge(id[i][j],id[0][j],inf); 68 } 69 printf("%d\n",sum-maxflow()); 70 return 0; 71 }
这是道结论题= =
某个啥啥定理说:DAG的最小链覆盖=最大独立点集,可见网格图的最大独立点集一定是从右上到左下的一条路径,那么我们就可以直接dp搞了
CODE:
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 #define maxn 1100 7 int f[maxn][maxn],a[maxn][maxn],T,n,m; 8 int main(){ 9 freopen("math.in","r",stdin); 10 freopen("math.out","w",stdout); 11 scanf("%d",&T); 12 while (T--) { 13 memset(f,0,sizeof(f)); 14 scanf("%d%d",&n,&m); 15 for (int i=1;i<=n;i++) 16 for (int j=1;j<=m;j++) scanf("%d",a[i]+j); 17 int ans=0; 18 for (int i=n;i;i--) 19 for (int j=1;j<=m;j++) { 20 f[i][j]=max(f[i][j-1],max(f[i+1][j-1]+a[i][j],f[i+1][j])); 21 ans=max(ans,f[i][j]); 22 } 23 printf("%d\n",ans); 24 } 25 return 0; 26 }
T3:[TJOI2015]弦论
这道题嘛= =,50分算法是深圳市选题,然后100分的话我们可以用SAM来解决这个问题
首先我们先来考虑一下50分的算法,SAM上的每一个节点都表示该图中的一个子串,所以我们可以类似dp求出答案
而对于T=1的时候,可以发现重复的字串其实都在以parents树上该节点为根的子树
所以我们还是可以dp一下求出来
八中上被卡常数了,老调不出来
CODE:
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 #define maxn 1001000 7 char s[maxn]; 8 typedef long long ll; 9 struct sam{ 10 sam *pre,*ch[26]; 11 int val,cnt;ll size; 12 bool b; 13 }_t[maxn]; 14 sam *root,*last; 15 int t,cnt; 16 inline void add(int x) { 17 sam *p=last; 18 _t[++cnt].val=last->val+1; 19 sam *np=_t+cnt; 20 while (p&&p->ch[x]==0) p->ch[x]=np,p=p->pre; 21 if (p==0) np->pre=root; 22 else { 23 sam* q=p->ch[x]; 24 if (p->val+1==q->val) np->pre=q; 25 else { 26 _t[++cnt].val=p->val+1; 27 sam*nq=_t+cnt; 28 memcpy(nq->ch,q->ch,sizeof(q->ch)); 29 nq->pre=q->pre; 30 np->pre=q->pre=nq; 31 while (p&&p->ch[x]==q) p->ch[x]=nq,p=p->pre; 32 } 33 } 34 last=np; 35 } 36 inline void bfs(){ 37 static sam* q[maxn]; 38 q[1]=root; 39 sam* u=q[1]; 40 int l,r; 41 for (l=r=1;l<=r;u=q[++l]) { 42 for (int i=0;i<26;i++) { 43 if (!u->ch[i]||u->ch[i]->b) continue; 44 u->ch[i]->b=1; 45 q[++r]=u->ch[i]; 46 } 47 } 48 u=q[r]; 49 for (int i=r;i;u=q[--i]) { 50 if (!t) u->cnt=1; 51 if (i==1) u->cnt=0; 52 if (u->pre) u->pre->cnt+=u->cnt; 53 } 54 } 55 char ans[maxn]; 56 int l; 57 void dfs(sam *p){ 58 int i; 59 p->b=0; 60 p->size=p->cnt; 61 for(i=0;i<26;i++) 62 if(p->ch[i]){ 63 if(p->ch[i]->b==1) dfs(p->ch[i]); 64 p->size+=p->ch[i]->size; 65 } 66 } 67 int k; 68 void get(sam *p){ 69 int i; 70 if(k<=p->cnt) return ; 71 k-=p->cnt; 72 for(i=0;i<26;i++) 73 if(p->ch[i]){ 74 if(k<=p->ch[i]->size){ 75 ans[++l]=i+'a'; 76 get(p->ch[i]); 77 return ; 78 } 79 k-=p->ch[i]->size; 80 } 81 } 82 int main(){ 83 scanf("%s%d%d",&s,&t,&k); 84 root=_t; 85 root->val=1;last=root; 86 int n=strlen(s); 87 for (int i=0;i<n;i++) { 88 add(s[i]-'a'); 89 last->cnt=1; 90 } 91 bfs(); 92 dfs(root); 93 if (root->size<k) { 94 printf("-1\n"); 95 return 0; 96 } 97 get(root); 98 printf("%s\n",ans+1); 99 return 0; 100 }