JLOI2015 解题报告

那个嘛= =,虽说是JLOI的解题报告但还差第一题没写= =,就这样行啦

T2:[JLOI2015]城池攻占

首先这道题我们先考虑暴力,也就是每个点向父亲跑,我们考虑能否一起做,可以发现在同一个点的骑士可以用一个堆维护一起跳(因为没有改变优先级的操作)然后再用懒标记维护,我们可以直接用一个可合并堆来维护就可以啦

当然这道题用线段树,倍增都是可行的,就是空间比较拙计罢了,需要用一些奇奇怪怪的方法来干

CODE:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef long long ll;
 7 struct node{
 8     node *l,*r;int id,dis;ll s,lx,ly;
 9     node(ll _s,int _id){
10         l=r=0;
11         s=_s,id=_id,lx=1,ly=0;dis=1;
12     }
13 };
14 inline void update(node* x) {
15     if (x->l) {
16         x->l->s*=x->lx;
17         x->l->s+=x->ly;
18         x->l->lx*=x->lx;
19         x->l->ly*=x->lx;
20         x->l->ly+=x->ly;
21     }
22     if (x->r) {
23         x->r->s*=x->lx;
24         x->r->s+=x->ly;
25         x->r->lx*=x->lx;
26         x->r->ly*=x->lx;
27         x->r->ly+=x->ly;
28     }
29     x->lx=1;x->ly=0;
30 }
31 node* merge(node* x,node *y) {
32     if (!x) return y;
33     if (!y) return x;
34     update(x);update(y);
35     if (x->s>y->s) swap(x,y);
36     x->r=merge(x->r,y);
37     if (!x->l||x->l->dis<x->r->dis) swap(x->l,x->r);
38     x->dis=x->r?x->r->dis+1:0;
39     return x;
40 }
41 inline node* del(node *x) {
42     update(x);
43     return merge(x->l,x->r);
44 }
45 #define maxn 300010
46 int dep[maxn],fa[maxn],a[maxn],ans[maxn],sum[maxn];
47 ll h[maxn],v[maxn];
48 node *root[maxn];
49 int main(){
50     freopen("fall.in","r",stdin);
51     freopen("fall.out","w",stdout);
52     int n,m;
53     scanf("%d%d",&n,&m);
54     for (int i=1;i<=n;i++) scanf("%lld",h+i);
55     dep[1]=1;
56     for (int i=2;i<=n;i++) {
57         scanf("%d%d%lld",fa+i,a+i,v+i);
58         dep[i]=dep[fa[i]]+1;
59     }
60     for (int i=1;i<=m;i++) {
61         ll s;int c;
62         scanf("%lld%d",&s,&c);
63         root[c]=merge(root[c],new node(s,i));
64         ans[i]=dep[c];
65     }
66     for (int i=n;i;i--) {
67         while (root[i]&&root[i]->s<h[i]) {
68             sum[i]++;
69             ans[root[i]->id]-=dep[i];
70             root[i]=del(root[i]);
71         }
72         if (!root[i]) continue;
73         if (a[i]==0) {
74             root[i]->s+=v[i];
75             root[i]->ly+=v[i];
76         }
77         else {
78             root[i]->s*=v[i];
79             root[i]->lx*=v[i];
80             root[i]->ly*=v[i];
81         }
82         root[fa[i]]=merge(root[fa[i]],root[i]);
83     }
84     for (int i=1;i<=n;i++) printf("%d\n",sum[i]);
85     for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
86     return 0;
87 }

T3:[JLOI2015]装备购买

首先这个其实是求一个代价最小的最大线性无关集合(不会去线性代数把),线性无关集合也就是指在该集合中没有一个向量能由该集合的其他向量组成

所以该集合其实就是一组基,那么我们可以每次用高斯消元判断当前的向量是否能由其他向量组成,如果不行的话就加入答案了

求代价最小就排个序即可

CODE:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 #define maxn 510
 7 double a[maxn][maxn];
 8 int c[maxn];
 9 const double epx=1e-4;
10 inline bool zero(double x) {return x>-epx&&x<epx;}
11 int main(){
12     freopen("purchase.in","r",stdin);
13     freopen("purchase.out","w",stdout);
14     int n,m;
15     scanf("%d%d",&n,&m);
16     int l=1,ans=0;
17     for (int i=1;i<=n;i++)
18         for (int j=1;j<=m;j++) scanf("%lf",a[i]+j);
19     for (int i=1;i<=n;i++) scanf("%d",&c[i]);
20     c[0]=1000000;
21     for (int i=1;i<=m;i++) {
22         int id=0;
23         for (int j=l;j<=n;j++)
24             if (!zero(a[j][i])&&c[id]>c[j]) id=j;
25         if (id==0) continue;
26         for (int j=1;j<=m;j++) swap(a[l][j],a[id][j]);
27         swap(c[id],c[l]);
28         ans+=c[l];
29         for (int j=l+1;j<=n;j++) {
30             double t=a[j][i]/a[l][i];
31             for (int k=i;k<=m;k++) a[j][k]-=a[l][k]*t;
32         }
33         l++;
34     }
35     printf("%d %d\n",l-1,ans);
36     return 0;
37 }

T4:[JLOI2015]骗我呢

这道题比较奇葩啦

首先我们考虑每一行,可以发现是单调递减的,并且肯定只缺了一个格,所以我们设f[i][j]为第i行缺j的方案数

可得f[i][j]=sigma(f[i-1][k]) k<=j+1

也就是f[i][j]=f[i][j-1]+f[i-1][j+1]

发现这个形式长得很像组合数,也可想求组合数那样看成求路径数。

我们把第i行向右平移i位,那么这个图就变成这样了

也就是把求这样子的路径方案数。

我们考虑先记下组合数那样的矩形图,再如何去掉左下和右上的点

很明显我们可以将终点按y=-x-1那条线镜面反射即可。

右上角也相似,但可能出现:左上->右下的情况,所以我们还要再去掉这种情况

...

这样推下去

CODE:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 typedef long long ll;
 7 #define mod 1000000007
 8 #define maxn 3001000
 9 ll fac[maxn],inv[maxn];
10 int n,m;
11 inline ll c(int x,int y) {
12     return fac[x]*1ll*inv[y]%mod*inv[x-y]%mod;
13 }
14 inline void _swap1(int &x,int &y) {
15     swap(x,y);
16     x--,y++;
17 }
18 inline void _swap2(int &x,int &y) {
19     swap(x,y);
20     x+=m+2,y-=m+2;
21 }
22 int main(){
23     freopen("pwn.in","r",stdin);
24     freopen("pwn.out","w",stdout);
25     scanf("%d%d",&n,&m);
26     fac[0]=fac[1]=1;
27     inv[0]=inv[1]=1;
28     for (int i=2;i<=n+n+m+10;i++) {
29         fac[i]=fac[i-1]*i%mod;
30         inv[i]=(mod-mod/i)*inv[mod%i]%mod;
31     }
32     for (int i=1;i<=n+m+n+10;i++) (inv[i]=inv[i]*inv[i-1])%=mod;
33     int x=n+m+1,y=n;
34     ll ans=c(x+y,y);
35     for (;;) {
36         _swap1(x,y);
37         if (x<0||y<0) break;
38         (ans-=c(x+y,y))%=mod;
39         _swap2(x,y);
40         if (x<0||y<0) break;
41         (ans+=c(x+y,y))%=mod;
42     }
43     x=n+m+1,y=n;
44     for (;;) {
45         _swap2(x,y);
46         if (x<0||y<0) break;
47         (ans-=c(x+y,y))%=mod;
48         _swap1(x,y);
49         if (x<0||y<0) break;
50         (ans+=c(x+y,y))%=mod;
51     }
52     printf("%d\n",(ans+mod)%mod);
53     return 0;
54 }

T5:[JLOI2015]管道连接

这是一个叫斯坦纳树的东西= =,以前知道但没写过,今天终于写了一次了

首先我们可以记f[i][j]为点的联通状态为i,经过点j的距离最小值,那么有两种状态转移

i的转移f[i][j]=max(f[k][j]+f[i^k][j])k为i的子集

j的转移:我们先求出i的转移,然后一边spfa即可

这样可以证明是正确的

这样我们就求出了一组点的答案,那么多组点我们可以用一个dp来合并答案

写起来还是挺舒服的,很多东西都能用这个东西解决,插头dp啊什么的

CODE:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 using namespace std;
 7 #define maxk 1030
 8 #define maxn 1100000
 9 #define maxm 3100
10 #define inf 0x7fffffff
11 struct edges{
12     int to,next,dist;
13 }edge[maxm*2];
14 int next[maxk],l;
15 inline void addedge(int x,int y,int z) {
16     edge[++l]=(edges){y,next[x],z};next[x]=l;
17 }
18 typedef pair<int,int> ii;
19 #define fi first
20 #define se second
21 int f[maxk][maxk],n,p,a[15],c[15];
22 priority_queue<ii,vector<ii>,greater<ii> > q;
23 bool b[maxk];
24 inline void dij(){
25     for (int i=1;i<1<<p;i++)
26         for (int j=1;j<=n;j++) f[i][j]=inf;
27     for (int i=0;i<p;i++) f[1<<i][a[i+1]]=0;
28     for (int i=1;i<1<<p;i++) {
29         while (!q.empty()) q.pop();
30         memset(b,0,sizeof(b));
31         for (int j=(i-1)&i;j>0;j=(j-1)&i)
32             for (int k=1;k<=n;k++) f[i][k]=min(f[i][k],f[j][k]+f[i^j][k]);
33         int *dist=f[i];
34         for (int j=1;j<=n;j++) {
35             if (dist[j]==inf) continue;
36             q.push(ii(dist[j],j));
37         }
38         int cnt=0;
39         while (!q.empty()) {
40             ii u=q.top();q.pop();
41             if (b[u.se]) continue;
42             b[u.se]=1;cnt++;
43             if (cnt==n) break;
44             for (int i=next[u.se];i;i=edge[i].next)
45                 if (edge[i].dist+dist[u.se]<dist[edge[i].to]){
46                     dist[edge[i].to]=edge[i].dist+dist[u.se];
47                     q.push(ii(dist[edge[i].to],edge[i].to));
48                 }
49         }
50     }
51 }
52 int g[maxk],d[15];
53 inline int get(int x) {
54     int ans=0;
55     for (int i=1;x;i++,x>>=1) if (x&1) ans|=d[i];
56     return ans;
57 }
58 int main(){
59     freopen("channel.in","r",stdin);
60     freopen("channel.out","w",stdout);
61     int m;
62     scanf("%d%d%d",&n,&m,&p);
63     for (int i=1;i<=m;i++) {
64         int u,v,w;
65         scanf("%d%d%d",&u,&v,&w);
66         addedge(u,v,w);
67         addedge(v,u,w);
68     }
69     for (int i=1;i<=p;i++) scanf("%d%d",c+i,a+i);
70     dij();
71     for (int i=1;i<=p;i++) d[c[i]]|=1<<(i-1);
72     for (int i=1;i<1<<p;i++) {
73         g[i]=inf;
74         int x=get(i);
75         for (int j=1;j<=n;j++) g[i]=min(g[i],f[x][j]);
76     }
77     for (int i=1;i<1<<p;i++)
78         for (int j=(i-1)&i;j>0;j=(j-1)&i)
79             g[i]=min(g[i],g[j]+g[i^j]);
80     printf("%d\n",g[(1<<p)-1]);
81     return 0;
82 }

T6:[JLOI2015]战争调度
这道题还是挺不错的,jloi考了好多要让你算空间的题- -

记f[i][j][k]为第i个节点祖先状态为j有k个儿子选择战争的最小答案,那么我们考虑一下这样的状态数以及转移复杂度

第i层的节点祖先状态有2^i儿子数有2^n-i一共有2^n个状态,所以总状态数为4^n

每个节点的转移是O(k)的,总的时间复杂度就是n*4^n,可以解决本题

这个主要还是得考你对时间和空间复杂度的分析= =

CODE:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<map>
 6 using namespace std;
 7 typedef pair<int,int>ii;
 8 typedef pair<int,ii> iii;
 9 #define maxn 1030
10 int n,m,w[2][maxn][13],ans;
11 map<iii,int> ma;
12 int dfs(int x,int y,int z,int size) {
13     if (ma.find(iii(x,ii(y,z)))!=ma.end()) return ma[iii(x,ii(y,z))];
14     int s=0;
15     if (x>=(1<<(n-1))) {
16         x-=(1<<(n-1))-1;
17         for (int i=0;i<n-1;i++) s+=((y>>i)&1)==z?w[z][x][i]:0;
18         ma[iii(x+(1<<(n-1))-1,ii(y,z))]=s;
19         return s;
20     }
21     for (int i=0;i<=z;i++) {
22         if (i>(size>>1)||z-i>(size>>1)) continue;
23         s=max(s,max(dfs(x<<1,y<<1,i,size>>1)+dfs((x<<1)^1,y<<1,z-i,size>>1),dfs(x<<1,(y<<1)^1,i,size>>1)+dfs((x<<1)^1,(y<<1)^1,z-i,size>>1)));
24     }
25     ma[iii(x,ii(y,z))]=s;
26     return s;
27 }
28 int main(){
29     freopen("war.in","r",stdin);
30     freopen("war.out","w",stdout);
31     scanf("%d%d",&n,&m);
32     for (int i=1;i<=1<<(n-1);i++)
33         for (int j=0;j<n-1;j++) scanf("%d",w[1][i]+j);
34     for (int i=1;i<=1<<(n-1);i++)
35         for (int j=0;j<n-1;j++) scanf("%d",w[0][i]+j);
36     for (int i=0;i<=m;i++) ans=max(ans,dfs(1,0,i,1<<(n-1)));
37     printf("%d\n",ans);
38 }

好啦总结一下这套题吧= =

首先我觉得出得太noi化了没有省选的感觉,但又没有noi那么难,有种四不像的感觉

很多题目的想法都很值得学习,而且题解的ppt上的总结写得非常好

总的来说还是值得一刷的

时间: 2024-10-19 10:13:29

JLOI2015 解题报告的相关文章

解题报告 之 POJ3057 Evacuation

解题报告 之 POJ3057 Evacuation Description Fires can be disastrous, especially when a fire breaks out in a room that is completely filled with people. Rooms usually have a couple of exits and emergency exits, but with everyone rushing out at the same time

hdu 1541 Stars 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1541 题目意思:有 N 颗星星,每颗星星都有各自的等级.给出每颗星星的坐标(x, y),它的等级由所有比它低层(或者同层)的或者在它左手边的星星数决定.计算出每个等级(0 ~ n-1)的星星各有多少颗. 我只能说,题目换了一下就不会变通了,泪~~~~ 星星的分布是不是很像树状数组呢~~~没错,就是树状数组题来滴! 按照题目输入,当前星星与后面的星星没有关系.所以只要把 x 之前的横坐标加起来就可以了

【百度之星2014~初赛(第二轮)解题报告】Chess

声明 笔者最近意外的发现 笔者的个人网站http://tiankonguse.com/ 的很多文章被其它网站转载,但是转载时未声明文章来源或参考自 http://tiankonguse.com/ 网站,因此,笔者添加此条声明. 郑重声明:这篇记录<[百度之星2014~初赛(第二轮)解题报告]Chess>转载自 http://tiankonguse.com/ 的这条记录:http://tiankonguse.com/record/record.php?id=667 前言 最近要毕业了,有半年没做

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告 勘误1:第6题第4个 if最后一个条件粗心写错了,答案应为1580. 条件应为abs(a[3]-a[7])!=1,宝宝心理苦啊.!感谢zzh童鞋的提醒. 勘误2:第7题在推断连通的时候条件写错了,后两个if条件中是应该是<=12 落了一个等于号.正确答案应为116. 1.煤球数目 有一堆煤球.堆成三角棱锥形.详细: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形), 第四层10个(排列成三角形). -. 假设一共

[noip2011]铺地毯(carpet)解题报告

最近在写noip2011的题,备战noip,先给自己加个油! 下面是noip2011的试题和自己的解题报告,希望对大家有帮助,题目1如下 1.铺地毯(carpet.cpp/c/pas) [问题描述]为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有n 张地毯,编号从1 到n.现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上.地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的

ACdream 1203 - KIDx&#39;s Triangle(解题报告)

KIDx's Triangle Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) Submit Statistic Next Problem Problem Description One day, KIDx solved a math problem for middle students in seconds! And than he created this problem. N

解题报告 之 CodeForces 91B Queue

解题报告 之 CodeForces 91B Queue Description There are n walruses standing in a queue in an airport. They are numbered starting from the queue's tail: the 1-st walrus stands at the end of the queue and the n-th walrus stands at the beginning of the queue.

解题报告 之 POJ1226 Substrings

解题报告 之 POJ1226 Substrings Description You are given a number of case-sensitive strings of alphabetic characters, find the largest string X, such that either X, or its inverse can be found as a substring of any of the given strings. Input The first li

解题报告 之 UVA563 Crimewave

解题报告 之 UVA563 Crimewave Description Nieuw Knollendam is a very modern town. This becomes clear already when looking at the layout of its map, which is just a rectangular grid of streets and avenues. Being an important trade centre, Nieuw Knollendam a