TJOI2015 day1解题报告

博客园的编辑器真的是太蛋疼了= =,想用tex然后上jpg又贴不了链接,真的很纠结啊= =

T1:[TJOI2015]线性代数

描述:戳上面吧= =

首先这道题我觉得是这套题最漂亮的一道题了(虽然说学校的题库里居然有一道和这个一模一样的= =)

首先我们可以先把那个式子转化为其中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 }
View Code

T2:[TJOI2015]组合数学

这是道结论题= =

某个啥啥定理说: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 }
View Code

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 }
View Code

 

posted @ 2015-04-28 21:35  New_Godess  阅读(281)  评论(0编辑  收藏  举报