好久不寫題,外加上在準(zhǔn)備考研,這次有點(diǎn)悲劇,比賽時(shí)A了5題,還有一題有點(diǎn)小BUG,比賽后才A。。今年要考南京大學(xué)~也沒時(shí)間準(zhǔn)備ICPC了,希望我們隊(duì)里的那個(gè)小孩子能夠快快成長起來,我這個(gè)隊(duì)長也可以安心的卸任了,明年將最后一次比賽機(jī)會(huì)放在NJU吧~恩,順便去看下高中膜拜過的蔣炎研同學(xué)~江蘇大學(xué)加油!
第一題:
其實(shí)就是構(gòu)建一個(gè)DAG,然后再DAG上求最長路徑。要注意構(gòu)圖時(shí)候避免環(huán),特別考慮當(dāng)兩個(gè)木塊長寬都一致而且都是d=0類型的時(shí)候。對了,還有一個(gè)陰險(xiǎn)的地方,長寬可以互換的~復(fù)雜度O(n2)
1
# include <cstdio>
2
# include <cstring>
3
# include <algorithm>
4
using namespace std;
5
int n;
6
# define N 1005
7
# define M 1000005
8
int data[N][4];
9
int g[N],nxt[M],v[M],val[M],c;
10
long long len[N];
11
long long dp(int pos)
12

{
13
if(len[pos]!=-1) return len[pos];
14
else
15
{
16
len[pos]=0;
17
for(int p=g[pos];p!=-1;p=nxt[p])
18
len[pos]=max(len[pos],dp(v[p])+val[p]);
19
return len[pos];
20
}
21
}
22
void insert(int s,int e,int value)
23

{
24
v[c]=e;
25
val[c]=value;
26
nxt[c]=g[s];
27
g[s]=c++;
28
}
29
int main()
30

{
31
while(scanf("%d",&n)&&n)
32
{
33
for(int i=0;i<n;i++)
34
{
35
scanf("%d%d%d%d",&data[i][0],&data[i][1],&data[i][2],&data[i][3]);
36
if(data[i][0]>data[i][1]) swap(data[i][0],data[i][1]);
37
}
38
memset(g,-1,sizeof(g));
39
memset(len,-1,sizeof(len));
40
c=0;
41
for(int i=0;i<n;i++)
42
for(int j=0;j<n;j++)
43
switch(data[i][3])
44
{
45
case 0:
46
if(data[j][0]<=data[i][0]&&data[j][1]<=data[i][1]&&!(data[j][0]==data[i][0]&&data[j][1]==data[i][1]&&data[j][3]==data[i][3]&&j>=i))
47
insert(i,j,data[j][2]);
48
break;
49
case 1:
50
if(data[j][0]<=data[i][0]&&data[j][1]<=data[i][1]&&((long long)data[j][0]*data[j][1])<((long long)data[i][0]*data[i][1]))
51
insert(i,j,data[j][2]);
52
break;
53
case 2:
54
if(data[j][0]<data[i][0]&&data[j][1]<data[i][1])
55
insert(i,j,data[j][2]);
56
break;
57
};
58
for(int i=0;i<n;i++)
59
insert(n,i,data[i][2]);
60
printf("%I64d\n",dp(n));
61
}
62
return 0;
63
} 第二題:一個(gè)數(shù)論題目,當(dāng)時(shí)沒有證明,直接找規(guī)律的,具體的就是質(zhì)數(shù)連成。恩。代碼是隊(duì)里的大一的孩子寫的,就直接貼了。復(fù)雜度打好表的畫就是個(gè)二分查找的復(fù)雜度
1
#include<cstdio>
2
#include<cmath>
3
#include<cstdlib>
4
#include<cstring>
5
6
using namespace std;
7
8
const int tablesize=64;
9
const int primesize=2000;
10
bool isprime[primesize+1];
11
int pt[primesize];
12
int mytable[tablesize+1][150];
13
inline void multiple(int* a,int b);
14
void getprime(int n);
15
void getmytable(int tablesize);
16
void getdata_and_solve();
17
void find_the_ans(char* ts);
18
void zhuanhuan(int* a,char* ts);
19
int dayu(int* a,int* b);
20
21
int main()
22

{
23
getprime(primesize);
24
getmytable(tablesize);
25
getdata_and_solve();
26
return 0;
27
}
28
29
inline void multiple(int* a,int b)
30

{
31
int len=a[0];
32
int i;
33
a[1]*=b;
34
for (i=2;i<=len;++i)
35
{
36
a[i]=a[i]*b+a[i-1]/10;
37
a[i-1]%=10;
38
}
39
while (a[len]>9)
{++len; a[len]=a[len-1]/10; a[len-1]%=10;}
40
a[0]=len;
41
}
42
43
void getprime(int n)
44

{
45
int i;
46
for (i=1;i<=n;++i) isprime[i]=true;
47
isprime[1]=false;
48
int j;
49
i=1;
50
while (++i<=n)
51
if (isprime[i])
52
{
53
j=i;
54
while ((j+=i)<=n)
55
isprime[j]=false;
56
}
57
pt[0]=0;
58
for (i=1;i<=n;++i)
59
if (isprime[i]) pt[++pt[0]]=i;
60
}
61
62
void getmytable(int tablesize)
63

{
64
int j,i,len;
65
mytable[1][0]=1; mytable[1][1]=2;
66
for (i=2;i<=tablesize;++i)
67
{
68
len=mytable[i-1][0];
69
for (j=0;j<=len;++j)
70
mytable[i][j]=mytable[i-1][j];
71
multiple(mytable[i],pt[i]);
72
}
73
}
74
75
void getdata_and_solve()
76

{
77
char ts[200];
78
int n;
79
scanf("%d",&n);
80
getchar();
81
int i;
82
for (i=1;i<=n;++i)
83
{
84
gets(ts);
85
find_the_ans(ts);
86
}
87
}
88
89
void find_the_ans(char* ts)
90

{
91
int l=1,r=tablesize;
92
int mid;
93
int shuju[150];
94
zhuanhuan(shuju,ts);
95
int lena,lenb=shuju[0];
96
int flag;
97
int i;
98
while (l+1<r)
99
{
100
mid=((l+r)>>1);
101
lena=mytable[mid][0];
102
if (lena>lenb) flag=1; //a>b;
103
else
104
if (lena<lenb) flag=-1; //a<b;
105
else
106
{
107
flag=0;
108
for (i=lena;i>=1;--i)
109
{
110
if (mytable[mid][i]>shuju[i])
{flag=1; break;}
111
else if (mytable[mid][i]<shuju[i])
{flag=-1; break;}
112
}
113
}
114
115
if (flag==0)
{l=mid; break;}
116
else if(flag==1) r=mid;
117
else l=mid;
118
}
119
120
for (i=mytable[l][0];i>=1;--i) printf("%d",mytable[l][i]);
121
putchar('\n');
122
}
123
124
void zhuanhuan(int* a,char* ts)
125

{
126
int len=strlen(ts);
127
int i;
128
for (i=0;i<len;++i)
129
a[len-i]=ts[i]-'0';
130
a[0]=len;
131
}
132
1003 是個(gè)TREE-DP,好久不動(dòng)了,不敢寫。。等會(huì)來實(shí)現(xiàn)下
1004 一個(gè)二分+驗(yàn)證的問題。先二分最長長度,然后用BFS驗(yàn)證。其實(shí)都不用BFS,因?yàn)槭莻€(gè)嚴(yán)格單調(diào)的序列,直接DFS更簡單
1
# include <cstdio>
2
# include <algorithm>
3
# include <queue>
4
using namespace std;
5
int n,m,l;
6
# define N 500005
7
int d[N],dis[N];
8
queue<int> q;
9
bool chk(int len)
10

{
11
if(len>=l) return true;
12
while(!q.empty()) q.pop();
13
int pos=upper_bound(d,d+n,len)-d-1;
14
if(pos<0) return false;
15
dis[pos]=1;
16
if(m<=dis[pos]) return false;
17
q.push(pos);
18
while(!q.empty())
19
{
20
int top=q.front();
21
q.pop();
22
if(d[top]+len>=l) return true;
23
pos=upper_bound(d,d+n,d[top]+len)-d-1;
24
if(pos<0||d[pos]<=d[top]||dis[top]+1>=m) return false;
25
dis[pos]=dis[top]+1;
26
q.push(pos);
27
}
28
return false;
29
}
30
int main()
31

{
32
while(scanf("%d%d%d",&l,&n,&m)!=EOF)
33
{
34
for(int i=0;i<n;i++)
35
scanf("%d",d+i);
36
sort(d,d+n);
37
int s=0,e=l;
38
while(s<=e)
39
{
40
int mid=(s+e)/2;
41
if(chk(mid)) e=mid-1;
42
else s=mid+1;
43
}
44
printf("%d\n",e+1);
45
}
46
return 0;
47
} 1005 木有思想
1006這題NC了,當(dāng)時(shí)想都沒想直接手寫樹狀數(shù)組+二分,現(xiàn)在想想看這題條件太特殊了,詢問的位置是一定的,就是一個(gè)簡單的最小堆= =。。。不過還是把樹狀數(shù)組的NC版本代碼貼出來吧。。
1007 一個(gè)經(jīng)典的動(dòng)態(tài)統(tǒng)計(jì),我寫這類題目時(shí)都會(huì)很偷懶的用STL的set,呵呵~
1008 比賽時(shí)間來不及了,當(dāng)時(shí),以為寫出5題,能夠穩(wěn)了,yzu的同學(xué)來了個(gè)電話,說這次比賽5題已經(jīng)排到150了。。大驚。。連忙回去看題。。但是。。哎。。
不扯淡了,寫寫這題思想。看復(fù)雜度,非O(n)的算法不行的說
差不多定下來是TREE-DP
首先構(gòu)造以1為根的樹
然后主要解決3個(gè)問題
1、判斷詢問時(shí)X節(jié)點(diǎn)是再Y節(jié)點(diǎn)的子孫節(jié)點(diǎn)還是其祖先節(jié)點(diǎn)(相對于以1為根的樹)
2、分別討論以上兩種情況下的解
第一問我是這樣解決的
首先記錄下以1為根的樹的dfn(DFS遍歷序列),如果X是Y的子孫節(jié)點(diǎn)當(dāng)且僅當(dāng)dfn(x)>=dfn(y)且dfn(x)<=max(dfn(z)),z是y的子孫節(jié)點(diǎn)。這里要tree-dp處理max(dfn(z))。
第二問的解決就很銷魂了
首先,如果X是Y的祖先節(jié)點(diǎn),那么問題就轉(zhuǎn)化為求以Y為根的子樹的問題,可以直接利用以1為根的樹的DP出來的結(jié)果。(即以K為根的子樹兒子編號的最小值以及子孫編號的最小值以及次小值(這個(gè)后面會(huì)說有什么用),這個(gè)TREE-DP大家肯定都會(huì)的)
X是Y的兒子節(jié)點(diǎn)
這個(gè)麻煩一點(diǎn),首先利用DFN可以很快的確定根在Y的哪棵子樹上,如果最小值取在這棵子樹上,那么取Y的次小值,否則就取最小值。然后如果Y節(jié)點(diǎn)不是1號節(jié)點(diǎn)的話,其最小兒子(相對于以Y為根的子樹)編號再與其父親(相對于以1為根的子樹)取個(gè)最小值,最小子孫(相對于以Y為根的子樹)編號與1取最小值。
然后上代碼~
1
# include <cstdio>
2
# include <vector>
3
# include <algorithm>
4
# define max(a,b) ((a)>(b)?(a):(b))
5
using namespace std;
6
# define N 100005
7
vector<int> g[N];
8
int dfn[N],c=0,maxdfn[N];
9
int n,q;
10
int dp[N],fa[N];
11
int ans[N][5];
12
void update(int tmp[],int pos)
13

{
14
if(pos<tmp[0]) tmp[1]=tmp[0],tmp[0]=pos;
15
else if(pos<tmp[1]) tmp[1]=pos;
16
if(dp[pos]<tmp[2]) tmp[3]=tmp[2],tmp[2]=dp[pos],tmp[4]=pos;
17
else if(dp[pos]<tmp[3]) tmp[3]=dp[pos];
18
}
19
void dfs(int pos,int pre)
20

{
21
dp[pos]=pos;
22
maxdfn[pos]=dfn[pos]=c++;
23
ans[pos][0]=ans[pos][1]=ans[pos][2]=ans[pos][3]=0xfffffff;
24
for(int i=0;i<g[pos].size();i++)
25
if(g[pos][i]!=pre)
26
{
27
dfs(g[pos][i],pos);
28
if(dp[g[pos][i]]<dp[pos])
29
dp[pos]=dp[g[pos][i]];
30
maxdfn[pos]=max(maxdfn[pos],maxdfn[g[pos][i]]);
31
update(ans[pos],g[pos][i]);
32
}
33
34
fa[pos]=pre;
35
}
36
int main()
37

{
38
int t;
39
scanf("%d",&t);
40
while(t--)
41
{
42
scanf("%d%d",&n,&q);
43
for(int i=1;i<=n;i++) g[i].clear();
44
for(int i=1;i<n;i++)
45
{
46
int a,b;
47
scanf("%d%d",&a,&b);
48
g[a].push_back(b);
49
g[b].push_back(a);
50
}
51
c=0;
52
dfs(1,1);
53
54
while(q--)
55
{
56
int x,y;
57
scanf("%d%d",&x,&y);
58
if(dfn[x]<dfn[y]||dfn[x]>maxdfn[y])//根在上方
59
{
60
int ans1=ans[y][0],ans2=ans[y][2];
61
if(ans1==0xfffffff) printf("no answers!\n");
62
else printf("%d %d\n",ans1,ans2);
63
}
64
else//根在子樹中
65
{
66
int ans1=(dfn[x]>=dfn[ans[y][0]]&&dfn[x]<=maxdfn[ans[y][0]]?ans[y][1]:ans[y][0]),
67
ans2=(dfn[x]>=dfn[ans[y][4]]&&dfn[x]<=maxdfn[ans[y][4]]?ans[y][3]:ans[y][2]);
68
if(y!=1) ans1=min(ans1,fa[y]),ans2=min(ans2,1);
69
if(ans1==0xfffffff) printf("no answers!\n");
70
else printf("%d %d\n",ans1,ans2);
71
}
72
}
73
printf("\n");
74
}
75
return 0;
76
} 1009 當(dāng)時(shí)沒來得及看,小朋友太純真的說費(fèi)用流,我就無語了。。不過這事都是給了我啟發(fā)。。不會(huì)想到有向圖的最小生成樹的時(shí)候太遲了。。
1010 不知道
最后再次祝福ujs Genius_Cats 在解體前能夠有個(gè)好成績~
Genius Cats 隊(duì)長:yzhw