生活随笔
收集整理的這篇文章主要介紹了
2019-10-5 NOIP模拟赛多校联考——Round7 题解
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
T1 整數(shù)分解
裸的完全背包……被孫到
把2i2^i2i當作物品,容量為nnn
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
#define mod 1000000007
using namespace std
;
typedef long long ll
;
int read() {re x
=0,f
=1;char ch
=getchar();while(ch
<'0' || ch
>'9') {if(ch
=='-') f
=-1;ch
=getchar();}while(ch
>='0' && ch
<='9') {x
=10*x
+ch
-'0';ch
=getchar();}return x
*f
;
}
const int Size
=1000005;
int n
,dp
[Size
],LOG
[Size
];
int main() {
n
=read();dp
[0]=1;for(re i
=0; i
<=20; i
++) {for(re j
=0; j
+(1<<i
)<=n
; j
++) {dp
[j
+(1<<i
)]=(dp
[j
+(1<<i
)]+dp
[j
])%mod
;}}printf("%d",dp
[n
]);return 0;
}
T2 貧富差距
u,vu,vu,v是朋友就建一條u,vu,vu,v的邊。
如果所有的點都在同一個聯(lián)通塊中,那么貧富差距的最大值就是最長鏈的長度乘以ddd(易證無法構造出更大的貧富差距)。
判-1用并查集,判是否所有的點在同一個聯(lián)通塊中即珂,如果有兩個點不在同一個聯(lián)通塊中,則這兩個點的貧富差距珂以無限擴大。
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
#define mod 1000000007
using namespace std
;
int read() {re x
=0,f
=1;char ch
=getchar();while(ch
<'0' || ch
>'9') {if(ch
=='-') f
=-1;ch
=getchar();}while(ch
>='0' && ch
<='9') {x
=10*x
+ch
-'0';ch
=getchar();}return x
*f
;
}
inline char GetChar() {char ch
=getchar();while(ch
!='Y' && ch
!='N') ch
=getchar();return ch
;
}
const int Size
=105;
int n
,d
,father
[Size
];
int Find(int x
) {if(x
==father
[x
]) return x
;return father
[x
]=Find(father
[x
]);
}
int cnt
,head
[Size
];
struct node
{int v
,next
;
} w
[Size
*Size
<<1];
inline void AddEdge(int u
,int v
) {w
[++cnt
].v
=v
;w
[cnt
].next
=head
[u
];head
[u
]=cnt
;
}
int Queue
[Size
],dis
[Size
];
bool vis
[Size
];
int bfs(int s
) {memset(vis
,0,sizeof(vis
));int hd
=0,tl
=0;Queue
[++tl
]=s
;vis
[s
]=true;dis
[s
]=0;int ans
=0;while(hd
<tl
) {int x
=Queue
[++hd
];for(re i
=head
[x
]; i
; i
=w
[i
].next
) {int nxt
=w
[i
].v
;if(!vis
[nxt
]) {vis
[nxt
]=true;Queue
[++tl
]=nxt
;dis
[tl
]=dis
[hd
]+1;if(dis
[tl
]>ans
) {ans
=dis
[tl
];}}}}return ans
;
}
inline void init() {memset(head
,0,sizeof(head
));cnt
=0;for(re i
=1; i
<=n
; i
++) {father
[i
]=i
;}
}
int main() {
int T
=read();while(T
--) {n
=read();d
=read();init();for(re i
=1; i
<=n
; i
++) {for(re j
=1; j
<=n
; j
++) {char ch
=GetChar();if(ch
=='Y') {AddEdge(i
,j
);int fx
=Find(i
);int fy
=Find(j
);if(fx
!=fy
) {father
[fx
]=fy
;}}}}int fa
=Find(1);bool inf
=false;for(re i
=2; i
<=n
; i
++) {if(Find(i
)!=fa
) {inf
=true;break;}}if(inf
) {puts("-1");continue;}int ans
=0;for(re i
=1; i
<=n
; i
++) {int now
=bfs(i
);if(now
>ans
) {ans
=now
;}}printf("%d\n",ans
*d
);}return 0;
}
T3 特殊的排列
找出序列上相鄰兩項差為1的最長子序列,則這個子序列長度是最長的不用移動的長度。
證明:
1.移動一個子序列之外的數(shù),子序列的相對順序不變。
2.不在最長子序列中的數(shù)一定要移動到序列首或序列末(否則珂以形成更長的相鄰兩項差為1的子序列)。
3.不存在另一個更長的子序列,相鄰兩項差不為1,且這個子序列中的數(shù)不用移動。因為若相鄰兩項差不為1,那么這兩項之間的數(shù)必須要通過移動子序列里的數(shù)來得到。
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
using namespace std
;
int read() {re x
=0,f
=1;char ch
=getchar();while(ch
<'0' || ch
>'9') {if(ch
=='-') f
=-1;ch
=getchar();}while(ch
>='0' && ch
<='9') {x
=(x
<<1)+(x
<<3)+ch
-'0';ch
=getchar();}return x
*f
;
}
const int Size
=50005;
int dp
[Size
];
int main() {int n
=read();int ans
=0;for(re i
=1; i
<=n
; i
++) {int x
=read();if((dp
[x
]=dp
[x
-1]+1)>ans
) {ans
=dp
[x
];}}printf("%d",n
-ans
);return 0;
}
T4 極品飛車
一個特殊的隱含條件是速度必須要>0,否則時間會變成負數(shù)或正無窮(長者:只有我才能操控負數(shù)和+∞+\infin+∞的時間,你們還是太naive)
列出式子,d1s1+c+d2s2+c+...+dnsn+c=t\frac{d_1}{s_1+c}+\frac{d_2}{s_2+c}+...+\frac{d_n}{s_n+c}=ts1?+cd1??+s2?+cd2??+...+sn?+cdn??=t
因為對于任意iii,有si+c>0s_i+c>0si?+c>0,所以左邊是單調遞減的。
所以二分ccc,暴力判即珂。
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
#define mod 1000000007
#define eps 1e-10
using namespace std
;
int read() {re x
=0,f
=1;char ch
=getchar();while(ch
<'0' || ch
>'9') {if(ch
=='-') f
=-1;ch
=getchar();}while(ch
>='0' && ch
<='9') {x
=10*x
+ch
-'0';ch
=getchar();}return x
*f
;
}
inline char GetChar() {char ch
=getchar();while(ch
!='Y' && ch
!='N') ch
=getchar();return ch
;
}
const int Size
=1005;
int n
;
double t
,s
[Size
],d
[Size
];
double check(double mid
) {double ans
=0;for(re i
=1; i
<=n
; i
++) {if(fabs(s
[i
]+mid
)<eps
) {ans
+=1e15;} else {ans
+=d
[i
]/(s
[i
]+mid
);}}return ans
;
}
int main() {
n
=read();scanf("%lf",&t
);double minn
=1e10;for(re i
=1; i
<=n
; i
++) {scanf("%lf %lf",&d
[i
],&s
[i
]);if(s
[i
]<minn
) minn
=s
[i
];}double l
=-minn
+eps
,r
=1e7,mid
;for(re i
=1; i
<=1000; i
++) {mid
=(l
+r
)/2;if(check(mid
)>=t
) {l
=mid
;} else {r
=mid
;}}printf("%.6lf",l
);return 0;
}
T5 修改數(shù)組
首先把所有a[i]a[i]a[i]都減去iii,然后題目變成修改一些數(shù),要求改成非負整數(shù),且滿足序列不減。
把所有a[i]>=0a[i]>=0a[i]>=0的a[i]a[i]a[i]提取出來,跑最長不降子序列。因為序列不減,所以剩下的a[i]<0a[i]<0a[i]<0的部分一定能改成一個非負整數(shù),使序列不減。
最后只有這個LIS的所有元素不用修改。
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
using namespace std
;
int read() {re x
=0,f
=1;char ch
=getchar();while(ch
<'0' || ch
>'9') {if(ch
=='-') f
=-1;ch
=getchar();}while(ch
>='0' && ch
<='9') {x
=(x
<<1)+(x
<<3)+ch
-'0';ch
=getchar();}return x
*f
;
}
const int Size
=100005;
int n
,maxn
,a
[Size
],b
[Size
],tree
[Size
];
inline int lowbit(int x
) {return x
&(-x
);
}
inline void update(int x
,int v
) {for(re i
=x
; i
<=maxn
; i
+=lowbit(i
)) {if(v
>tree
[i
]) {tree
[i
]=v
;}}
}
inline int query(int x
) {int ans
=0;for(re i
=x
; i
; i
-=lowbit(i
)) {if(tree
[i
]>ans
) {ans
=tree
[i
];}}return ans
;
}
int main() {n
=read();int tot
=0;for(re i
=1; i
<=n
; i
++) {a
[i
]=read()-i
;if(a
[i
]>=0) {b
[++tot
]=a
[i
];}}for(re i
=1; i
<=tot
; i
++) {a
[i
]=b
[i
];}sort(a
+1,a
+1+tot
);maxn
=unique(a
+1,a
+1+tot
)-(a
+1);for(re i
=1; i
<=tot
; i
++) {b
[i
]=lower_bound(a
+1,a
+1+maxn
,b
[i
])-a
;}int ans
=0;for(re i
=1; i
<=tot
; i
++) {int x
=query(b
[i
]);update(b
[i
],x
+1);if(x
+1>ans
) {ans
=x
+1;}}printf("%d",n
-ans
);return 0;
}
T6 小Biu看電影
不知道為什么珂以暴力dfs……
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#define re register int
#define mod 1000000007
using namespace std
;
int read() {re x
=0,f
=1;char ch
=getchar();while(ch
<'0' || ch
>'9') {if(ch
=='-') f
=-1;ch
=getchar();}while(ch
>='0' && ch
<='9') {x
=10*x
+ch
-'0';ch
=getchar();}return x
*f
;
}
const int Size
=300005;
const int INF
=0x3f3f3f3f;
int n
,m
,cnt
,head
[Size
];
struct Edge
{int v
,t
,next
;
} w
[Size
<<1];
void AddEdge(int u
,int v
,int c
) {w
[++cnt
].v
=v
;w
[cnt
].t
=c
;w
[cnt
].next
=head
[u
];head
[u
]=cnt
;
}
int ans
=INF
,val
[Size
],dis
[Size
];
void dfs(int x
,int sum
) {if(sum
>=ans
) return;if(sum
+val
[x
]<ans
) {ans
=sum
+val
[x
];}for(int i
=head
[x
]; i
; i
=w
[i
].next
) {int nxt
=w
[i
].v
;if(sum
+w
[i
].t
<dis
[nxt
]) {dis
[nxt
]=sum
+w
[i
].t
;dfs(nxt
,sum
+w
[i
].t
);}}
}
int main() {
n
=read();m
=read();for(re i
=1; i
<=n
; i
++) {val
[i
]=read();}for(re i
=1; i
<=m
; i
++) {int u
=read();int v
=read();int c
=read()<<1;AddEdge(u
,v
,c
);AddEdge(v
,u
,c
);}for(re i
=1; i
<=n
; i
++) {memset(dis
,0x3f,sizeof(dis
));ans
=val
[i
];dfs(i
,0);printf("%d\n",ans
);}return 0;
}
正解:
建一個虛點sss,從sss向所有iii連邊權為val[i]val[i]val[i]的邊,跑dijkstra。
然后sss到每個點的距離就是從這個點開始能看到電影的最小花費(容易看出最小花費就是sss到一個點的最短距離,因為一開始建了邊權為val[i]val[i]val[i]的邊)。
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<queue>
#define re register int
#define mod 1000000007
using namespace std
;
int read() {re x
=0,f
=1;char ch
=getchar();while(ch
<'0' || ch
>'9') {if(ch
=='-') f
=-1;ch
=getchar();}while(ch
>='0' && ch
<='9') {x
=10*x
+ch
-'0';ch
=getchar();}return x
*f
;
}
const int Size
=100005;
const int INF
=0x3f3f3f3f;
int n
,m
,cnt
,head
[Size
];
struct Edge
{int v
,t
,next
;
} w
[600005];
void AddEdge(int u
,int v
,int c
) {w
[++cnt
].v
=v
;w
[cnt
].t
=c
;w
[cnt
].next
=head
[u
];head
[u
]=cnt
;
}
struct node
{int x
,t
;
};
inline bool operator < (const node a
,const node b
) {return a
.t
>b
.t
;
}
int dis
[Size
];
void Dijkstra(int s
) {memset(dis
,0x3f,sizeof(dis
));priority_queue
<node
> Q
;Q
.push((node
){s
,0});dis
[s
]=0;while(!Q
.empty()) {int x
=Q
.top().x
;Q
.pop();for(re i
=head
[x
]; i
; i
=w
[i
].next
) {int nxt
=w
[i
].v
;if(dis
[x
]+w
[i
].t
<dis
[nxt
]) {dis
[nxt
]=dis
[x
]+w
[i
].t
;Q
.push((node
){nxt
,dis
[nxt
]});}}}
}
int main() {
n
=read();m
=read();int s
=n
+1;for(re i
=1; i
<=n
; i
++) {int x
=read();AddEdge(s
,i
,x
);}for(re i
=1; i
<=m
; i
++) {int u
=read();int v
=read();int c
=read()<<1;AddEdge(u
,v
,c
);AddEdge(v
,u
,c
);}Dijkstra(s
);for(re i
=1; i
<=n
; i
++) {printf("%d\n",dis
[i
]);}return 0;
}
總結
以上是生活随笔為你收集整理的2019-10-5 NOIP模拟赛多校联考——Round7 题解的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。