文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>10.11-16的模拟赛

10.11-16的模拟赛

时间:2010-11-16  来源:LitIce

【问题描述】

有n个炸弹,有些炸弹牵了一根单向引线(也就是说引线只有在这一端能被炸弹点燃),只要引爆了这个炸弹,用引线连接的下一个炸弹也会爆炸。每个炸弹还有个得分,当这个炸弹被引爆后就能得到相应得分。

现在要你引爆k个炸弹,使得分最大。

 

【输入格式】

第1行两个整数n、k。

接下来n行每行两个整数a[i]、b[i]。a[i]表示这个炸弹用引线连接的下一个炸弹,如果a[i]为0,则表示这个炸弹没连接引线。b[i]表示这个炸弹的得分。

 

【输出格式】

  仅一个数,表示最大得分。

 

【输入样例】bomb.in

8 2

0 1

1 1

2 100

2 100

0 1

5 1

6 2

6 2

 

【输出样例】bomb.out

202

 

【数据规模】

1≤b[i]≤1000000

对于30%的数据,n≤1000  k≤30

对于60%的数据,n≤50000 k≤100 

对于100%的数据,n≤200000   k≤500

--------------------------------------------------------------------------------------------

考试的时候没想出来T T。

Algorithm:

先缩环成点,这样就变成了一棵树。(题目特殊可以dfs缩点,代码里还是打了tarjan)

贪心取出一条最大链,删掉后再重复这个过程。(不用真的删除只要Dp时处理一下就可以了)

最后排序所有取出的链,排序取前m大。

 

代码
  1 #include<iostream>
2 #include<cstdio>
3 #define N 300001
4 #define LL long long
5 using namespace std;
6 struct node{
7 LL y,next;
8 } E[N];
9
10 LL DFN[N],Low[N],S[N],inS[N],col,color[N],edg[N],f[N];
11 LL index,Ecnt,n,m,x;
12 LL a[N],c[N],b[N],aa[N],cc,bo[N],cnt,vis[N],root,ans;
13 void add_edge(LL x,LL y)
14 {
15 ++Ecnt;E[Ecnt].y=y;E[Ecnt].next=edg[x];edg[x]=Ecnt;
16 }
17 void tarjan(LL u)
18 {
19 DFN[u]=Low[u]=++index;S[++cnt]=u;inS[u]=1;
20
21 LL v;
22 for (LL j=edg[u];j!=0;j=E[j].next)
23 {
24 v=E[j].y;
25 if (DFN[v]==0)
26 {
27 tarjan(v);
28 if (Low[v]<Low[u]) Low[u]=Low[v];
29
30 }
31 else
32 if (inS[v]==1 && Low[v]<Low[u]) Low[u]=Low[v];
33 }
34
35 if (DFN[u]==Low[u])
36 {
37 ++col;
38 while (cnt>0 && Low[S[cnt]]==DFN[u])
39 {
40 color[S[cnt]]=col;
41 --cnt;
42 }
43 }
44 }
45 LL dp(LL u)
46 {
47 if (bo[u]) return f[u];
48 bo[u]=1;
49
50 LL v,Big=0,bi;
51 for (LL j=edg[u];j!=0;j=E[j].next)
52 {
53 v=E[j].y;
54 if (dp(v)>Big) Big=dp(v),bi=v;
55 }
56 f[u]=Big+b[u];
57 for (LL j=edg[u];j!=0;j=E[j].next)
58 {
59 if (E[j].y!=bi) vis[E[j].y]=1;
60 }
61 return f[u];
62 }
63 int main()
64 {
65 freopen("bomb.in","r",stdin);
66 freopen("bomb.out","w",stdout);
67 scanf("%d%d",&n,&m);
68 for (LL i=1;i<=n;++i)
69 {
70 scanf("%d%d",&x,&c[i]);
71 a[i]=x;
72 add_edge(x,i);
73 }
74 for (LL i=0;i<=n;++i)
75 if (DFN[i]==0) tarjan(i);
76 // for (LL i=0;i<=n;++i)
77 // printf("%d %d\n",i,color[i]);
78 Ecnt=0;for (LL i=1;i<=col;++i) edg[i]=0;
79
80 for (LL i=1;i<=n;++i)
81 if (color[a[i]]!=color[i])
82 add_edge(color[a[i]],color[i]);
83
84 for (LL i=1;i<=n;++i)
85 b[color[i]]+=c[i];
86
87 root=color[0];
88
89 for (LL i=1;i<=col;++i) bo[i]=0;
90 vis[root]=1;
91 dp(root);
92
93 cc=0;
94 for (LL i=1;i<=col;++i) if (vis[i])
95 {
96 ++cc;
97 aa[cc]=f[i];
98 }
99 sort(aa+1,aa+cc);
100 while (cc>0 && m>0)
101 {
102 ans+=aa[cc];
103 --cc;--m;
104 }
105 cout<<ans<<endl;
106 return 0;
107 }
108

 

 

---------------------------------------------------------------------------------------------

【问题描述】

有若干个圆饼套在一根柱子里,形成了一个汉诺塔(圆饼从上到下依次编号为1~p),我们想把汉诺塔从0号柱子移到n+1号柱子,中间有n个柱子和m块空地给我们使用。移动规则如下:

  1. 从0号柱子移出的圆饼不能移回0号柱子,移到n+1号柱子的圆饼不能再移动。
  2. I号圆饼只能放在I+1号圆饼上、空地上和柱子最下面。
  3. 空地上只能放一个圆饼,而柱子上可以按规则2形成汉诺塔。
  4. 可以直接将圆饼从0号柱子移到n+1号柱子。

现在我们有n个柱子和m块空地可以使用,问你最多可以将多高的汉诺塔从0号柱子移到n+1号柱子(高度是指形成汉诺塔的圆饼数目)。由于高度可能很大,所以只需你求出高度mod k的值。

 

【输入格式】

只有一行,为三个正整数n,m,k,三个数分别用空格隔开。

 

【输出格式】

只有一个数,为最大高度mod k的值。

 

【输入样例】tower.in

1 1 10

 

【输出样例】tower.out

4

 

【数据规模】 

对于50%的数据n,m,k<=103

对于80%的数据n,m,k<=106

对于100%的数据n,m,k<=109

 

 ---------------------------------------------------------------------------------------------

推出公式:ans=2^n*(m+1)% k;

 

先不考虑空地。假设空地为数为0

手动算出

F(0)=1 (直接从0->n+1)

F(1)=2

F(2)=4

就可以预测F(3)=8

0        1  2 3  4

从0->1通过2,3最多可移动 4个

从0->2通过3最多可移动 2个

从0->3 最多可移动1个

从0->4 移动1个

3->4 移动1个

2->4 通过 3  移动2个

1->4 通过 2 3 移动4 个。

这样就完成了8个的移动

于是F(n)>=2^n; 

现在证明F(n)<=2^n

F(0),F(1),F(2)满足条件

因为最大的那个盘要移动0->n+1缩以中间的所有柱子都只能够先粗村

F(3)时比F(2)多了一根柱子储存,他最多只能储存F(2)个盘子,

故F(3)<=2*F(2);命题得证

现在再考虑空地 空地就相当于吧每一次移动一个盘变成移动m+1个盘

(显然我们可以先把m+1个中的m个先分散到空地,第m+1个移动到目标后,再将m个

移动过去)

相关阅读 更多 +
排行榜 更多 +
坦克冒险大师安卓版

坦克冒险大师安卓版

策略塔防 下载
自动防御

自动防御

策略塔防 下载
枪战大乱斗2

枪战大乱斗2

飞行射击 下载