T1:
簡述一下題意,就是每天給你預算和一個點,讓你用這個點到1的路徑上的點做完全背包,問最大收益。
點數詢問數<=5000,預算<=20000,時間限制1s,空間限制20Mb。
注意考試時是沒有給預算的正確數據范圍的,題意也不是很清晰,然后就棄療了......(題意不明怪我嘍)
考慮暴力怎么做,我們可以大力完全背包,時間空間復雜度都是O(ne)的。
可是顯然會MLE啊......
考慮用時間換空間(計算機比你想象的快到不知道哪里去了),如果我們能把空間復雜度的n優化為logn,時間復雜度再多個log也沒事啊。
我們可以?樹上cdq分治。
首先將詢問離線,把詢問全都放到點上。
考慮我們的分治結構,為樹上的一個子聯通塊,我們已知這個聯通塊最高點到根的背包值。然后如何處理?
我們找出塊重心,先遞歸包含最高點的部分。
然后暴力用重心到最高點的一條鏈上的權值和最高點的背包值求出重心的背包值,處理重心上的詢問。
最后枚舉重心的孩子,暴力處理出其背包值,然后遞歸計算。
時間復雜度O(nelogn),由于最多遞歸logn層,所以空間復雜度O(elogn)。
代碼:
1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 #include<vector>
5 const int maxn=5e3+1e2,maxe=2e4+
1e2;
6 const int inf=
0x3f3f3f3f;
7
8 struct Query{
int siz,id; };
9 int s[maxn],t[maxn<<
1],nxt[maxn<<
1],fa[maxn];
10 int cst[maxn],val[maxn],f[
17][maxe];
11 int siz[maxn],mxs[maxn],ban[maxn];
12 int ans[maxn];
13 std::vector<Query>
qs[maxn];
14
15 inline
void addedge(
int from,
int to) {
16 static int cnt;
17 t[++cnt] = to , nxt[cnt] = s[
from] , s[
from] =
cnt;
18 }
19 inline
void trans(
int* dst,
const int &cst,
const int &
val) {
20 for(
int i=cst;i<maxe;i++) dst[i] = std::max( dst[i] , dst[i-cst] +
val );
21 }
22
23 inline
void getrt(
int pos,
int fa,
const int &fs,
int &
rt) {
24 siz[pos] =
1 , mxs[pos] =
0;
25 for(
int at=s[pos];at;at=nxt[at])
if( t[at] != fa && !ban[t[at]] ) getrt(t[at],pos,fs,rt) , siz[pos] += siz[t[at]] , mxs[pos] =
std::max( mxs[pos] , siz[t[at]] );
26 if( ( mxs[pos] = std::max( mxs[pos] , fs - siz[pos]) ) < mxs[rt] ) rt =
pos;
27 }
28 inline
void solve(
int pos,
int fs,
int dep) {
// pos is the highest point in this block , assert we know dp[pos] in f[dep].
29 if( fs ==
1 ) {
30 for(unsigned i=
0;i<qs[pos].size();i++) ans[qs[pos][i].id] =
f[dep][qs[pos][i].siz];
31 return void(ban[pos]=
1);
32 }
33 int rt =
0;
34 *mxs = inf , getrt(pos,-
1,fs,rt) , ban[rt] =
1;
35 if( rt != pos ) memcpy(f[dep+
1],f[dep],
sizeof(f[
0])) , solve(pos,fs-siz[rt],dep+
1);
36 for(
int i=rt;i!=pos;i=
fa[i]) trans(f[dep],cst[i],val[i]);
37 for(unsigned i=
0;i<qs[rt].size();i++) ans[qs[rt][i].id] =
f[dep][qs[rt][i].siz];
38 for(
int at=s[rt];at;at=nxt[at])
if( !ban[t[at]] ) memcpy(f[dep+
1],f[dep],
sizeof(f[
0])) , trans(f[dep+
1],cst[t[at]],val[t[at]]) , solve(t[at],siz[t[at]],dep+
1);
39 }
40
41 int main() {
42 static int n,m;
43 scanf(
"%d%d",&n,&
m);
44 for(
int i=
1;i<=n;i++) scanf(
"%d%d",cst+i,val+
i);
45 for(
int i=
2;i<=n;i++) scanf(
"%d",fa+
i) , addedge(fa[i],i) , addedge(i,fa[i]);
46 for(
int i=
1;i<=m;i++) scanf(
"%d",ans+
i);
47 for(
int i=
1,pos;i<=m;i++) scanf(
"%d",&pos) , qs[pos].push_back((Query){ans[i],i}) , ans[i] =
0;
48 trans(f[
1],cst[
1],val[
1]) , solve(
1,n,
1);
49 for(
int i=
1;i<=m;i++) printf(
"%d\n",ans[i]);
50 return 0;
51 }
View Code
T2:
這都是什么東西啊......
考慮暴力,中間沒有特殊值的可以線段樹,前面的25分?n^2暴力吧,能不能過看臉了。
寫了,拍了,沒錯,感覺穩了。
然后評測下來發現只有10分!然后發現我賦值min和賦值max打反了,對拍的暴力的主函數是粘過去的,也是錯的......
于是身敗名裂。
這件事告訴我們對拍的暴力不要粘貼正解中除了頭文件、變量聲明和IO優化(如果有)以外的任何東西。因為你永遠不知道你會在哪里出錯。
正解棄坑啦!
10分代碼:
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 #include<tr1/unordered_set>
6 #define debug cerr
7 typedef
long long int lli;
8 using namespace std;
9
10 int n,m;
11
12 namespace SubTask1 {
13 const int maxn=5e3+
1e2;
14 const lli inf=
0x3f3f3f3f3f3f3f3fll;
15 lli
in[maxn];
16 tr1::unordered_set<lli>
ban;
17
18 inline
void initban() {
19 lli cur =
23;
20 for(
int i=
1;i<=
17;i++) cur = cur *
10 +
3 , ban.insert(cur);
21 }
22 inline
void apply_add(
int l,
int r,
const lli &
x) {
23 for(
int i=l;i<=r;i++)
in[i] +=
x;
24 }
25 inline
void apply_fil(
int l,
int r,
const lli &
x) {
26 for(
int i=l;i<=r;i++)
in[i] =
x;
27 }
28 inline lli query_sum(
int l,
int r) {
29 lli ret =
0;
30 for(
int i=l;i<=r;i++) ret +=
in[i];
31 return ret;
32 }
33 inline lli query_mi(
int l,
int r) {
34 lli ret =
inf;
35 for(
int i=l;i<=r;i++) ret = min( ret ,
in[i] );
36 return ret;
37 }
38 inline lli query_mx(
int l,
int r) {
39 lli ret = -
inf;
40 for(
int i=l;i<=r;i++) ret = max( ret ,
in[i] );
41 return ret;
42 }
43 inline
bool judge_ban(
int l,
int r) {
44 for(
int i=l;i<=r;i++)
if( ban.find(
in[i]) != ban.end() )
return 1;
45 return 0;
46 }
47 void main() {
48 initban();
49 for(
int i=
1;i<=n;i++) scanf(
"%lld",
in+
i);
50 for(
int i=
1,o,l,r,x;i<=m;i++
) {
51 scanf(
"%d",&
o);
52 if( o ==
1 ) scanf(
"%d",&x) , printf(
"%lld\n",query_sum(x,x));
53 else {
54 scanf(
"%d%d",&l,&
r);
55 if( o ==
2 || o ==
3 ) {
56 scanf(
"%d",&
x);
57 if( o ==
2 ) apply_fil(l,r,x);
58 else if( o ==
3 ) apply_add(l,r,x);
59 }
else {
60 lli val;
61 if( o ==
4 ) val =
query_mi(l,r);
62 else if( o ==
5 ) val =
query_mx(l,r);
63 else if( o ==
6 ) val = query_sum(l,r) / ( r - l +
1 );
64 apply_fil(l,r,val);
65 }
66 if( o ==
2 || o ==
3 || o ==
6 )
while( judge_ban(l,r) ) apply_add(l,r,
1);
67 }
68 }
69 }
70 }
71
72 namespace SubTask2 {
73 const int maxn=1e5+
1e2;
74 int in[maxn];
75 struct SegmentTree {
76 int l[maxn<<
2],r[maxn<<
2],lson[maxn<<
2],rson[maxn<<
2],cnt;
77 lli lazy_add[maxn<<
2],lazy_fil[maxn<<
2],sum[maxn<<
2],mi[maxn<<
2],mx[maxn<<
2];
78 SegmentTree() { memset(lazy_fil,-
1,
sizeof(lazy_fil)) , cnt =
1; }
79 inline
void apply_add(
int pos,
const lli &
x) {
80 mi[pos] += x , mx[pos] += x , sum[pos] += x * ( r[pos] - l[pos] +
1 );
81 if( ~lazy_fil[pos] ) lazy_fil[pos] +=
x;
82 else lazy_add[pos] +=
x;
83 }
84 inline
void apply_fil(
int pos,
const lli &
x) {
85 mi[pos] = mx[pos] = lazy_fil[pos] = x , sum[pos] = x * ( r[pos] - l[pos] +
1 );
86 lazy_add[pos] =
0;
87 }
88 inline
void push(
int pos) {
// two marks will not appear at the same time .
89 if( ~lazy_fil[pos] ) apply_fil(lson[pos],lazy_fil[pos]) , apply_fil(rson[pos],lazy_fil[pos]) , lazy_fil[pos] = -
1;
90 if( lazy_add[pos] ) apply_add(lson[pos],lazy_add[pos]) , apply_add(rson[pos],lazy_add[pos]) , lazy_add[pos] =
0;
91 }
92 inline
void maintain(
int pos) {
93 sum[pos] = sum[lson[pos]] + sum[rson[pos]] , mi[pos] = min( mi[lson[pos]] , mi[rson[pos]] ) , mx[pos] =
max( mx[lson[pos]] , mx[rson[pos]] );
94 }
95 inline
void build(
int pos,
int ll,
int rr) {
96 if( ( l[pos] = ll ) == ( r[pos] = rr ) )
return void(sum[pos] = mi[pos] = mx[pos] =
in[ll]);
97 const int mid = ( ll + rr ) >>
1;
98 build(lson[pos]=++cnt,ll,mid) , build(rson[pos]=++cnt,mid+
1,rr) , maintain(pos);
99 }
100 inline
void update_fil(
int pos,
const int &ll,
const int &rr,
const lli &
x) {
101 if( rr < l[pos] || r[pos] < ll )
return;
102 if( ll <= l[pos] && r[pos] <= rr )
return apply_fil(pos,x);
103 push(pos) , update_fil(lson[pos],ll,rr,x) , update_fil(rson[pos],ll,rr,x) , maintain(pos);
104 }
105 inline
void update_add(
int pos,
const int &ll,
const int &rr,
const lli &
x) {
106 if( rr < l[pos] || r[pos] < ll )
return;
107 if( ll <= l[pos] && r[pos] <= rr )
return apply_add(pos,x);
108 push(pos) , update_add(lson[pos],ll,rr,x) , update_add(rson[pos],ll,rr,x) , maintain(pos);
109 }
110 inline lli query_mi(
int pos,
const int &ll,
const int &
rr) {
111 if( ll <= l[pos] && r[pos] <= rr )
return mi[pos];
112 push(pos);
const int mid = ( l[pos] + r[pos] ) >>
1;
113 if( rr <= mid )
return query_mi(lson[pos],ll,rr);
114 else if( ll > mid )
return query_mi(rson[pos],ll,rr);
115 else return min( query_mi(lson[pos],ll,rr) , query_mi(rson[pos],ll,rr) );
116 }
117 inline lli query_mx(
int pos,
const int &ll,
const int &
rr) {
118 if( ll <= l[pos] && r[pos] <= rr )
return mx[pos];
119 push(pos);
const int mid = ( l[pos] + r[pos] ) >>
1;
120 if( rr <= mid )
return query_mx(lson[pos],ll,rr);
121 else if( ll > mid )
return query_mx(rson[pos],ll,rr);
122 else return max( query_mx(lson[pos],ll,rr) , query_mx(rson[pos],ll,rr) );
123 }
124 inline lli query_sum(
int pos,
const int &ll,
const int &
rr) {
125 if( ll <= l[pos] && r[pos] <= rr )
return sum[pos];
126 push(pos);
const int mid = ( l[pos] + r[pos] ) >>
1;
127 if( rr <= mid )
return query_sum(lson[pos],ll,rr);
128 else if( ll > mid )
return query_sum(rson[pos],ll,rr);
129 else return query_sum(lson[pos],ll,rr) +
query_sum(rson[pos],ll,rr);
130 }
131 }sgt;
132 void main() {
133 for(
int i=
1;i<=n;i++) scanf(
"%d",
in+
i);
134 sgt.build(
1,
1,n);
135 for(
int i=
1,o,l,r,x;i<=m;i++
) {
136 scanf(
"%d",&
o);
137 if( o ==
1 ) scanf(
"%d",&x) , printf(
"%lld\n",sgt.query_sum(
1,x,x));
138 else {
139 scanf(
"%d%d",&l,&
r);
140 if( o ==
2 || o ==
3 ) {
141 scanf(
"%d",&
x);
142 if( o ==
2 ) sgt.update_fil(
1,l,r,x);
143 else sgt.update_add(
1,l,r,x);
144 }
else {
145 lli val;
146 if( o ==
4 ) val = sgt.query_mi(
1,l,r);
147 else if( o ==
5 ) val = sgt.query_mx(
1,l,r);
148 else if( o ==
6 ) val = sgt.query_sum(
1,l,r) / ( r - l +
1 );
149 sgt.update_fil(
1,l,r,val);
150 }
151 }
152 }
153 }
154 }
155
156 int main() {
157 scanf(
"%d%d",&n,&
m);
158 if( n <=
4000 && m <=
4000 ) SubTask1::main();
159 else SubTask2::main();
160 return 0;
161 }
View Code 50分暴力代碼:
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 #include<tr1/unordered_set>
6 #define debug cerr
7 typedef
long long int lli;
8 using namespace std;
9
10 int n,m;
11
12 namespace SubTask1 {
13 const int maxn=5e3+
1e2;
14 const lli inf=
0x3f3f3f3f3f3f3f3fll;
15 lli
in[maxn];
16 tr1::unordered_set<lli>
ban;
17
18 inline
void initban() {
19 lli cur =
23;
20 for(
int i=
1;i<=
17;i++) cur = cur *
10 +
3 , ban.insert(cur);
21 }
22 inline
void apply_add(
int l,
int r,
const lli &
x) {
23 for(
int i=l;i<=r;i++)
in[i] +=
x;
24 }
25 inline
void apply_fil(
int l,
int r,
const lli &
x) {
26 for(
int i=l;i<=r;i++)
in[i] =
x;
27 }
28 inline lli query_sum(
int l,
int r) {
29 lli ret =
0;
30 for(
int i=l;i<=r;i++) ret +=
in[i];
31 return ret;
32 }
33 inline lli query_mi(
int l,
int r) {
34 lli ret =
inf;
35 for(
int i=l;i<=r;i++) ret = min( ret ,
in[i] );
36 return ret;
37 }
38 inline lli query_mx(
int l,
int r) {
39 lli ret = -
inf;
40 for(
int i=l;i<=r;i++) ret = max( ret ,
in[i] );
41 return ret;
42 }
43 inline
bool judge_ban(
int l,
int r) {
44 for(
int i=l;i<=r;i++)
if( ban.find(
in[i]) != ban.end() )
return 1;
45 return 0;
46 }
47 void main() {
48 initban();
49 for(
int i=
1;i<=n;i++) scanf(
"%lld",
in+
i);
50 for(
int i=
1,o,l,r,x;i<=m;i++
) {
51 scanf(
"%d",&
o);
52 if( o ==
1 ) scanf(
"%d",&x) , printf(
"%lld\n",query_sum(x,x));
53 else {
54 scanf(
"%d%d",&l,&
r);
55 if( o ==
2 || o ==
3 ) {
56 scanf(
"%d",&
x);
57 if( o ==
2 ) apply_fil(l,r,x);
58 else if( o ==
3 ) apply_add(l,r,x);
59 }
else {
60 lli val;
61 if( o ==
4 ) val =
query_mx(l,r);
62 else if( o ==
5 ) val =
query_mi(l,r);
63 else if( o ==
6 ) val = query_sum(l,r) / ( r - l +
1 );
64 apply_fil(l,r,val);
65 }
66 if( o ==
2 || o ==
3 || o ==
6 )
while( judge_ban(l,r) ) apply_add(l,r,
1);
67 }
68 }
69 }
70 }
71
72 namespace SubTask2 {
73 const int maxn=1e5+
1e2;
74 int in[maxn];
75 struct SegmentTree {
76 int l[maxn<<
2],r[maxn<<
2],lson[maxn<<
2],rson[maxn<<
2],cnt;
77 lli lazy_add[maxn<<
2],lazy_fil[maxn<<
2],sum[maxn<<
2],mi[maxn<<
2],mx[maxn<<
2];
78 SegmentTree() { memset(lazy_fil,-
1,
sizeof(lazy_fil)) , cnt =
1; }
79 inline
void apply_add(
int pos,
const lli &
x) {
80 mi[pos] += x , mx[pos] += x , sum[pos] += x * ( r[pos] - l[pos] +
1 );
81 if( ~lazy_fil[pos] ) lazy_fil[pos] +=
x;
82 else lazy_add[pos] +=
x;
83 }
84 inline
void apply_fil(
int pos,
const lli &
x) {
85 mi[pos] = mx[pos] = lazy_fil[pos] = x , sum[pos] = x * ( r[pos] - l[pos] +
1 );
86 lazy_add[pos] =
0;
87 }
88 inline
void push(
int pos) {
// two marks will not appear at the same time .
89 if( ~lazy_fil[pos] ) apply_fil(lson[pos],lazy_fil[pos]) , apply_fil(rson[pos],lazy_fil[pos]) , lazy_fil[pos] = -
1;
90 if( lazy_add[pos] ) apply_add(lson[pos],lazy_add[pos]) , apply_add(rson[pos],lazy_add[pos]) , lazy_add[pos] =
0;
91 }
92 inline
void maintain(
int pos) {
93 sum[pos] = sum[lson[pos]] + sum[rson[pos]] , mi[pos] = min( mi[lson[pos]] , mi[rson[pos]] ) , mx[pos] =
max( mx[lson[pos]] , mx[rson[pos]] );
94 }
95 inline
void build(
int pos,
int ll,
int rr) {
96 if( ( l[pos] = ll ) == ( r[pos] = rr ) )
return void(sum[pos] = mi[pos] = mx[pos] =
in[ll]);
97 const int mid = ( ll + rr ) >>
1;
98 build(lson[pos]=++cnt,ll,mid) , build(rson[pos]=++cnt,mid+
1,rr) , maintain(pos);
99 }
100 inline
void update_fil(
int pos,
const int &ll,
const int &rr,
const lli &
x) {
101 if( rr < l[pos] || r[pos] < ll )
return;
102 if( ll <= l[pos] && r[pos] <= rr )
return apply_fil(pos,x);
103 push(pos) , update_fil(lson[pos],ll,rr,x) , update_fil(rson[pos],ll,rr,x) , maintain(pos);
104 }
105 inline
void update_add(
int pos,
const int &ll,
const int &rr,
const lli &
x) {
106 if( rr < l[pos] || r[pos] < ll )
return;
107 if( ll <= l[pos] && r[pos] <= rr )
return apply_add(pos,x);
108 push(pos) , update_add(lson[pos],ll,rr,x) , update_add(rson[pos],ll,rr,x) , maintain(pos);
109 }
110 inline lli query_mi(
int pos,
const int &ll,
const int &
rr) {
111 if( ll <= l[pos] && r[pos] <= rr )
return mi[pos];
112 push(pos);
const int mid = ( l[pos] + r[pos] ) >>
1;
113 if( rr <= mid )
return query_mi(lson[pos],ll,rr);
114 else if( ll > mid )
return query_mi(rson[pos],ll,rr);
115 else return min( query_mi(lson[pos],ll,rr) , query_mi(rson[pos],ll,rr) );
116 }
117 inline lli query_mx(
int pos,
const int &ll,
const int &
rr) {
118 if( ll <= l[pos] && r[pos] <= rr )
return mx[pos];
119 push(pos);
const int mid = ( l[pos] + r[pos] ) >>
1;
120 if( rr <= mid )
return query_mx(lson[pos],ll,rr);
121 else if( ll > mid )
return query_mx(rson[pos],ll,rr);
122 else return max( query_mx(lson[pos],ll,rr) , query_mx(rson[pos],ll,rr) );
123 }
124 inline lli query_sum(
int pos,
const int &ll,
const int &
rr) {
125 if( ll <= l[pos] && r[pos] <= rr )
return sum[pos];
126 push(pos);
const int mid = ( l[pos] + r[pos] ) >>
1;
127 if( rr <= mid )
return query_sum(lson[pos],ll,rr);
128 else if( ll > mid )
return query_sum(rson[pos],ll,rr);
129 else return query_sum(lson[pos],ll,rr) +
query_sum(rson[pos],ll,rr);
130 }
131 }sgt;
132 void main() {
133 for(
int i=
1;i<=n;i++) scanf(
"%d",
in+
i);
134 sgt.build(
1,
1,n);
135 for(
int i=
1,o,l,r,x;i<=m;i++
) {
136 scanf(
"%d",&
o);
137 if( o ==
1 ) scanf(
"%d",&x) , printf(
"%lld\n",sgt.query_sum(
1,x,x));
138 else {
139 scanf(
"%d%d",&l,&
r);
140 if( o ==
2 || o ==
3 ) {
141 scanf(
"%d",&
x);
142 if( o ==
2 ) sgt.update_fil(
1,l,r,x);
143 else sgt.update_add(
1,l,r,x);
144 }
else {
145 lli val;
146 if( o ==
4 ) val = sgt.query_mx(
1,l,r);
147 else if( o ==
5 ) val = sgt.query_mi(
1,l,r);
148 else if( o ==
6 ) val = sgt.query_sum(
1,l,r) / ( r - l +
1 );
149 sgt.update_fil(
1,l,r,val);
150 }
151 }
152 }
153 }
154 }
155
156 int main() {
157 scanf(
"%d%d",&n,&
m);
158 if( n <=
4000 && m <=
4000 ) SubTask1::main();
159 else SubTask2::main();
160 return 0;
161 }
View Code ?
T3:
感覺這次考試唯一的一道好題......
題意就是要你造出一棵生成樹滿足權值最小,數據中所有數字非負。
什么為什么是樹?因為不是樹顯然不優啊。
這種提交答案題首先要觀察數據發現特殊性質,然后分類。
我分了如下幾類:
測試點0本來就是一棵樹,直接順序輸出即可。
代碼:
1 #include<bits/stdc++.h>
2
3 int main() {
4 int n,m;
5 scanf(
"%d%d",&n,&
m);
6 for(
int i=
1;i<=m;i++) printf(
"%d\n",i);
7 return 0;
8 }
View Code 測試點1最多有一個環,tarjan縮一發邊雙然后枚舉刪邊(然而數據其實是一個大環,所以只有一個邊雙)。
代碼:
1 #include<bits/stdc++.h>
2 #define debug cerr
3 typedef
long long int lli;
4 using namespace std;
5 const int maxn=1e6+
1e2;
6
7 map<lli,
int>
app;
8 int s[maxn],t[maxn<<
1],nxt[maxn<<
1];
9 int dfn[maxn],low[maxn],stk[maxn],ins[maxn],vis[maxn],ban[maxn],top;
// ban will be 1 if bridge .
10 lli val[maxn],col[maxn],su,cv=
0x3f3f3f3f3f3f3f3f;
11 int n,m,ans;
12
13 inline
void coredge(
int from,
int to) {
14 static int cnt =
1;
15 t[++cnt] = to , nxt[cnt] = s[
from] , s[
from] =
cnt;
16 }
17 inline
void addedge(
int a,
int b) {
18 coredge(a,b) , coredge(b,a);
19 }
20
21 inline
void dfs(
int pos,
int fae) {
22 static int dd;
23 vis[pos] =
1 , low[pos] = dfn[pos] = ++
dd;
24 for(
int at=s[pos];at;at=nxt[at])
if( at != ( fae ^
1 ) ) {
25 if( !
vis[t[at]] ) {
26 dfs(t[at],at) , low[pos] =
min( low[pos] , low[t[at]] );
27 if( low[t[at]] > dfn[pos] ) ban[at>>
1] =
1;
28 }
else low[pos] =
min( low[pos] , dfn[t[at]] );
29 }
30 }
31
32 inline lli calc(
int edg) {
33 lli cs = app.size() - ( app[col[edg]] ==
1 );
34 return ( su - val[edg] ) *
cs;
35 }
36
37 int main() {
38 scanf(
"%d%d",&n,&
m);
39 for(
int i=
1,a,b;i<=m;i++) scanf(
"%d%d%lld%d",&a,&b,val+i,col+i) , addedge(a,b) , ++app[col[i]] , su +=
val[i];
40 dfs(
1,
0);
41 for(
int i=
1;i<=m;i++
) {
42 if( !ban[i] && calc(i) <= cv ) cv = calc(i) , ans =
i;
43 }
44 for(
int i=
1;i<=m;i++)
if( i != ans ) printf(
"%d\n",i);
45 return 0;
46 }
View Code 測試點2只有一種顏色,最接最小生成樹。
代碼:
1 #include<bits/stdc++.h>
2 typedef
long long int lli;
3 using namespace std;
4 const int maxn=1e5+1e2,maxe=1e6+
1e2;
5
6 int n,m;
7 lli ans;
8
9 struct Edge {
10 int u,v,id;
11 lli w;
12 friend
bool operator < (
const Edge &a,
const Edge &
b) {
13 return a.w <
b.w;
14 }
15 }es[maxe];
16
17 struct UnionFindSet {
18 int fa[maxn];
19 inline
int findfa(
int x) {
20 return fa[x] == x ? x : fa[x] =
findfa(fa[x]);
21 }
22 inline
bool merge(
int x,
int y) {
23 x = findfa(x) , y =
findfa(y);
24 return x == y ?
0 : fa[x] =
y;
25 }
26 inline
void init() {
27 for(
int i=
1;i<=n;i++) fa[i] =
i;
28 }
29 }ufs;
30
31 int main() {
32 scanf(
"%d%d",&n,&
m) , ufs.init();
33 for(
int i=
1;i<=m;i++) scanf(
"%d%d%lld%*d",&es[i].u,&es[i].v,&es[i].w) , es[i].id =
i;
34 sort(es+
1,es+
1+
m);
35 for(
int i=
1;i<=m;i++)
if( ufs.merge(es[i].u,es[i].v) ) ans += es[i].w , printf(
"%d\n",es[i].id);
36 return 0;
37 }
View Code 測試點3,5的顏色都比較少,我們可以狀壓枚舉顏色然后最小生成樹(測試點3編譯選項Ofast優化全開,臺式6代i5跑了半個小時QAQ)。
代碼:
1 #include<bits/stdc++.h>
2 typedef
long long int lli;
3 using namespace std;
4 const int maxn=1e5+1e2,maxe=1e6+
1e2;
5 const lli inf=
0x3f3f3f3f3f3f3f3fll;
6
7 int n,m;
8 lli ans=
inf;
9 set<
int>
cs;
10 int way[maxe],mem[maxe];
11
12 struct Edge {
13 int u,v,col,id;
14 lli w;
15 friend
bool operator < (
const Edge &a,
const Edge &
b) {
16 return a.w <
b.w;
17 }
18 }es[maxe];
19
20 struct UnionFindSet {
21 int fa[maxn];
22 inline
int findfa(
int x) {
23 return fa[x] == x ? x : fa[x] =
findfa(fa[x]);
24 }
25 inline
bool merge(
int x,
int y) {
26 x = findfa(x) , y =
findfa(y);
27 return x == y ?
0 : fa[x] =
y;
28 }
29 inline
void init() {
30 for(
int i=
1;i<=n;i++) fa[i] =
i;
31 }
32 }ufs;
33
34 inline
int getsiz(
int x) {
35 int ret =
0;
36 while(x) ++ret , x -= (x&-
x);
37 return ret;
38 }
39 inline lli calc(
int sta) {
40 lli ret =
0 , sel =
0; ufs.init();
41 for(
int i=
1;i<=m;i++)
if( ( es[i].col & sta ) && ufs.merge(es[i].u,es[i].v) ) ret += es[i].w , way[++sel]=
i;
42 return sel == n -
1 ? ret *
getsiz(sta) : inf;
43 }
44
45
46 int main() {
47 scanf(
"%d%d",&n,&
m) , ufs.init();
48 for(
int i=
1;i<=m;i++) scanf(
"%d%d%lld%d",&es[i].u,&es[i].v,&es[i].w,&es[i].col) , es[i].col =
1 << ( es[i].col -
1 ) , cs.insert(es[i].col) , es[i].id =
i;
49 sort(es+
1,es+
1+
m);
50 int ss =
1 <<
cs.size();
51 cerr<<
"inf = "<<inf<<
endl;
52 for(
int i=
1;i<=m;i++)
if( es[i].col >= ss ) cerr<<
"color size error!"<<endl , exit(
0);
53 for(
int i=
0;i<ss;i++
) {
54 lli cal =
calc(i);
55 if( cal < ans ) ans = cal , memcpy(mem,way,
sizeof(
int)*n) , cerr<<
"copy i = "<<i<<
endl;
56 }
57 for(
int i=
1;i<n;i++) printf(
"%d\n",es[mem[i]].id);
58 return 0;
59 }
View Code 剩下的測試點(4,6,7,8,9)沒發現啥特殊性質,直接上模擬退火(隨機數種子?當然是我老婆的名字啦)。
代碼:
1 #include<bits/stdc++.h>
2 typedef
long long int lli;
3 using namespace std;
4 const int maxn=1e3+1e2,maxe=1e4+
1e2;
5 const lli inf=
0x3f3f3f3f3f3f3f3fll;
6 const double eps=1e-
5,mul=
0.9999,lambda=
0.1,ini=
1e8;
7
8 int n,m;
9
10 struct UnionFindSet {
11 int fa[maxn];
12 inline
int findfa(
int x) {
13 return fa[x] == x ? x : fa[x] =
findfa(fa[x]);
14 }
15 inline
bool merge(
int x,
int y) {
16 x = findfa(x) , y =
findfa(y);
17 return x == y ?
0 : fa[x] =
y;
18 }
19 inline
void init() {
20 for(
int i=
1;i<=n;i++) fa[i] =
i;
21 }
22 }ufs;
23
24 struct Edge {
25 int u,v,val,col,id;
26 }es[maxe];
27
28 int cur[maxe],now[maxe],ans[maxe];
29 lli calc_cur,calc_now,calc_ans;
30 double temp;
31
32 inline lli calc() {
33 set<
int> cs; lli su =
0; ufs.init();
34 for(
int t=
1;t<=m;t++
) {
35 const int i =
cur[t];
36 if( ufs.merge(es[i].u,es[i].v) ) su +=
es[i].val , cs.insert(es[i].col);
37 }
38 return su *
cs.size();
39 }
40 inline
void printans() {
41 ufs.init();
42 for(
int t=
1;t<=m;t++
) {
43 const int i =
ans[t];
44 if( ufs.merge(es[i].u,es[i].v) ) printf(
"%d\n",es[i].id);
45 }
46 }
47 inline
void solve() {
48 memcpy(cur+
1,now+
1,
sizeof(
int)*m) , random_shuffle(cur+
1,cur+
1+m) , calc_cur =
calc();
49 if( calc_cur < calc_ans ) memcpy(ans+
1,cur+
1,
sizeof(
int)*m) , calc_ans =
calc_cur;
50 if( calc_cur < calc_now || ( temp > lambda && (
double) rand() / ( rand() +
1 ) > temp ) ) memcpy(now+
1,cur+
1,
sizeof(
int)*m) , calc_now =
calc_cur;
51 }
52 inline
void random_seq() {
53 int l = rand() % m +
1 , r = rand() % m +
1;
54 if( l >
r ) swap(l,r);
55 random_shuffle(cur+l,cur+r+
1);
56 }
57 inline
void solve2() {
58 memcpy(cur+
1,now+
1,
sizeof(
int)*m) , random_seq() , calc_cur =
calc();
59 if( calc_cur < calc_ans ) memcpy(ans+
1,cur+
1,
sizeof(
int)*m) , calc_ans =
calc_cur;
60 if( calc_cur < calc_now || ( temp > lambda && (
double) rand() / ( rand() +
1 ) > temp ) ) memcpy(now+
1,cur+
1,
sizeof(
int)*m) , calc_now =
calc_cur;
61
62 }
63 inline
void getans() {
64 calc_now = calc_ans =
inf;
65 for(
int i=
1;i<=m;i++) now[i] =
i;
66 for(temp=ini;temp>eps;temp*=
mul) solve();
67 for(
int i=
1;i<=m;i++) now[i] =
i;
68 calc_now =
inf;
69 for(temp=ini;temp>eps;temp*=
mul) solve2();
70 }
71
72
73 inline
void init() {
// it can work
74 static const char seed[] =
"KurenaiKisaragi";
75 uint su =
0 , li =
strlen(seed);
76 for(
uint i=
0;i<li;i++) su +=
seed[i];
77 srand(su);
78 }
79
80 int main() {
81 scanf(
"%d%d",&n,&
m) , init();
82 for(
int i=
1;i<=m;i++) scanf(
"%d%d%d%d",&es[i].u,&es[i].v,&es[i].val,&es[i].col) , es[i].id =
i;
83 getans() , printans();
84 return 0;
85 }
View Code 結果下來測試點0,1,2,3,5,7都A了,4,6掛得很慘,8,9的分數不算太低。
這題總分數下來全場第三,比兩個學弟低不少(人家一個隨機爬山爬到收斂,一個枚舉選邊顏色蒙特卡洛跑半個小時,好像還商量了(商量還行?))。
其實測試點4,6的顏色都比較少,正解都是先欽定割邊必選然后爆搜顏色+剪枝(你測試點1寫的tarjan怎么不知道拿過來用了?)。
依舊沒有rank1(什么提答大戰你這種續命選手還想rank1?),然而也沒有辦法啦。考掛自己菜......
為什么沒歌詞了?額......改天再補嘛。
(這都能拖延?我還是快滾粗吧)
轉載于:https://www.cnblogs.com/Cmd2001/p/9089836.html
總結
以上是生活随笔為你收集整理的20180525小测的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。