https://ac.nowcoder.com/acm/contest/13168
A 水题
B
发现奇数中间的块会被分隔,大块由好多小块组成。
#include <bits/stdc++.h>
using namespace std;
int main()
{
long long a,b;
cin>>a>>b;
long long ans = __gcd(a,b);
a /= ans;
b /= ans;
if(a & 1 && b & 1) cout<<ans;
else cout<<0;
return 0;
}
C水题
D水题
E
F
G概率DP
方程很简单,注意初始化就好
概率DP的0不是没有是,选了0个,是一种情况
#include <bits/stdc++.h>
using namespace std;
double dp[105][105];
double a[105];
bool cmp(double a,double b){
return a > b;
}
int main()
{
int n;scanf("%d",&n);
for(int i = 1;i <= n;i ++) scanf("%lf",&a[i]),a[i] /= 100;
sort(a + 1,a + 1 + n,cmp);
dp[0][0] = 1;
for(int i = 1;i <= n;i ++){
dp[i][0] = dp[i - 1][0] * (1 - a[i]);
}
for(int i = 1;i <= n;i ++){
for(int j = 1;j <= i;j ++){
//printf("%f\n",a[i]);
dp[i][j] = dp[i - 1][j - 1] * a[i];
dp[i][j] += dp[i - 1][j] * (1.0 - a[i]);
}
}
double ans,res;
res = 0;
for(int i = 1;i <= n;i ++){
ans = 0;
for(int j = 1;j <= i;j ++){
//printf("%.10f",dp[i][j]);
ans += dp[i][j] * pow((double)j,(double)j/(double)i);
}
res = max(res,ans);
}
printf("%.10f",res);
return 0;
}
H区间DP
找到互不相交的区间
三重循环,最外层是len,然后是起点,和分隔
每个len都会有新的
a
[
i
]
[
i
+
l
e
n
−
1
]
a[i][i + len - 1]
a[i][i+len−1]没有被更新过
#include <bits/stdc++.h>
using namespace std;
int dp[505][505],a[505][505];
int main()
{
int n;scanf("%d",&n);
for(int i = 1;i <= n;i ++)
for(int j =1;j <= n;j ++) scanf("%d",&a[i][j]);
for(int t = 1;t < n;t ++){
for(int j = 1;j <= n - t;j ++){
for(int k = j;k <= j + t;k ++){
dp[j][j + k] = max(dp[j][j + k],dp[j + 1][k - 1] + dp[k][j + k - 1] + a[j][k]);
}
}
}
printf("%d",dp[1][n]);
return 0;
}
I Floyd
两遍Floyd,不算难,题目的加油站已经疯狂提示Floyd
注意需要思考清楚在写,第一遍Floyd的目的是建立新图,在新图上跑第二遍Floyd
#include <bits/stdc++.h>
using namespace std;
const int Mn = 505;
#define ll long long
ll dis[Mn][Mn];
ll ans[Mn][Mn];
ll g[Mn][Mn];
int vis[Mn];
const ll inf = 0x3f3f3f3f3f3f3f3f;
int main()
{
ll n,m,k,d;
scanf("%lld%lld%lld%lld",&n,&m,&k,&d);
int a;
for(int i = 1;i <= k;i ++){
scanf("%d",&a);
vis[a] = 1;
}
memset(ans,0x3f,sizeof(ans));
memset(dis,0x3f,sizeof(dis));
int b;
ll c;
for(int i = 1;i <= m;i ++){
scanf("%d%d%lld",&a,&b,&c);
g[a][b] = g[b][a] = c;
dis[a][b] = dis[b][a] = c;
}
for(int k = 1;k <= n;k ++){
for(int i = 1;i <= n;i ++){
for(int j = 1;j <= n;j ++){
if(i == j) dis[i][j] = 0LL;
else dis[i][j] = min(dis[i][j],dis[i][k] + dis[k][j]);
}
}
}
//printf("%lld\n",dis[2][5]);
if(dis[1][n] == inf){
puts("stuck");
}else
if(dis[1][n] <= d){
printf("%lld\n",dis[1][n]);
}else{
vis[1] = vis[n] = 1;
for(int i = 1;i <= n;i ++){
if(vis[i] == 0) continue;
for(int j = 1;j <= n;j ++){
if(vis[j] == 0) continue;
if(dis[i][j] > d) ans[i][j] = inf;
else ans[i][j] = dis[i][j];
}
}
for(int k = 1;k <= n;k ++){
if(vis[k] == 0) continue;
for(int i = 1;i <= n;i ++){
if(vis[i] == 0) continue;
for(int j = 1;j <= n;j ++){
if(vis[j] == 0) continue;
if(i == j) ans[i][j] = 0LL;
else{
ans[i][j] = min(ans[i][j],ans[i][k] + ans[k][j]);
//printf("%lld %lld %lld %d %d %d\n",ans[i][j],ans[i][k],ans[k][j],i,j,k);
}
}
}
}
//printf("%lld\n",ans[2][5]);
if(ans[1][n] == inf){
puts("stuck");
}else printf("%lld",ans[1][n]);
}
return 0;
}
K 简单DP(实际上是递推)
外国就是喜欢出DP
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int Mn = 1e5 + 5;
ll dp[Mn][30];
int vis[30];
int lst[300];
char s[Mn];
int main()
{
scanf("%s",s + 1);
int n = strlen(s + 1);
ll ans = 0;
for(int i = 1;i <= n;i ++){
int t = s[i] - 'a' + 1;
dp[i][t] = dp[i - 1][t] + 1;
lst[t] = i;
for(int j = 1;j <= 26;j ++){
if(j == t) continue;
if(dp[i][t] - dp[lst[j]][t] == 1 && lst[j])
ans ++;
dp[i][j] = dp[i - 1][j];
}
}
cout<<ans;
return 0;
}
L 线段树
是过得比较麻烦的一道题了
需要注意的地方是
1、题目中的ans不是由单独区间就可以跟新出来的,所以返回值最好是整个结构体,方便代码短一些
2、从右往左和从左往右的关系,就是把真个数组倒过来就行了,倒过来之后ans同样适用
3、日期取模问题,先-1后+1
4、左右,右左问题,左右是从0开始,所以右左是从
n
+
1
n + 1
n+1开始
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int Mn = 1e5 + 5;
struct node{
ll mx,mi,ans;
}tree[20][Mn << 2];
ll a[20][Mn],d[Mn];
ll f[20] = {0,0,1,2,3,2,1,0};
#define mid ((l + r) >> 1)
#define lson now,p<<1,l,mid
#define rson now,p<<1|1,mid+1,r
inline void updata(int now,int p){
tree[now][p].mx = max(tree[now][p << 1].mx,tree[now][p<<1|1].mx);
tree[now][p].mi = min(tree[now][p << 1].mi,tree[now][p<<1|1].mi);
tree[now][p].ans = max(tree[now][p<<1].ans,max(tree[now][p<<1|1].ans,tree[now][p<<1|1].mx - tree[now][p << 1].mi));
}
void build(int now,int p,int l,int r){
if(l == r){
tree[now][p].mi = tree[now][p].mx = a[now][l];
tree[now][p].ans = 0;
return ;
}
build(lson);
build(rson);
updata(now,p);
//printf("%d %d %d %d %d\n",l,r,tree[now][p].ans,tree[now][p].mx,tree[now][p].mi);
}
node Query(int now,int p,int l,int r,int ql,int qr){
if(ql <= l && r <= qr){
return tree[now][p];
}
node ans,al,ar;
if(qr <= mid) return Query(lson,ql,qr);
if(ql > mid) return Query(rson,ql,qr);
al = Query(lson,ql,mid);
ar = Query(rson,mid + 1,qr);
ans.mi = min(al.mi,ar.mi);
ans.mx = max(al.mx,ar.mx);
ans.ans = max(al.ans,max(ar.ans,ar.mx - al.mi));
return ans;
}
int main(){
int n;scanf("%d",&n);
for(int i = 1;i <= n;i ++){
scanf("%lld%lld",&a[0][i],&d[i]);
}
int now = 0;
for(int i = 1;i <= 7;i ++){
now = i;
for(int j = 1;j <= n;j ++){
a[i][j] = a[0][j] + f[now] * d[j];
now ++;
now = (now - 1) % 7 + 1;
}
}
for(int i = 1;i <= 7;i ++) build(i,1,1,n);
for(int i = 1;i <= n / 2;i ++){
swap(a[0][i],a[0][n + 1 - i]);
swap(d[i],d[n + 1 - i]);
}
for(int i = 8;i <= 14;i ++){
now = i - 7;
for(int j = 1;j <= n;j ++){
a[i][j] = a[0][j] + f[now] * d[j];
now ++;
now = (now - 1) % 7 + 1;
}
}
for(int i = 8;i <= 14;i ++) build(i,1,1,n);
int q;scanf("%d",&q);
while(q--){
int l,r;scanf("%d%d",&l,&r);
int flag = 1;
if(l > r){
flag = 0;
l = n + 1 - l;
r = n + 1 - r;
}
int x = (l - 1) % 7 + 1;
int d = x - 1;
int nw = 1 - d;
nw += 7;
if(nw == 8) nw = 1;
if(flag == 0) nw += 7;
for(int i = 1;i <= n;i ++){
//printf("*%d ",a[nw][i]);
}
//puts("");
printf("%lld\n",Query(nw,1,1,n,l,r).ans);
}
return 0;
}
M 三分或者结论
相似三角形或者三分
可以当做三分练手题
#include <bits/stdc++.h>
using namespace std;
const double esp = 1e-7;
double w,g,h,r;
inline double s(double x){
double ans = sqrt((g - r) * (g - r) + x * x);
ans += sqrt((h - r) * (h - r) + (w - x) * (w - x));
return ans;
}
inline void Slove(){
scanf("%lf%lf%lf%lf",&w,&g,&h,&r);
double ans;
if(g > h) swap(g,h);
ans = sqrt(w * w + (h - g) * (h - g));
printf("%.10f ",ans);
ans = 1e30;
double l = 0,r = w;
double mid1,mid2;
while(r - l >= esp){
mid1 = l + (r - l) / 3.0;
mid2 = l + (r - l) / 3.0 * 2;
// printf("%.10f %.10f %.10f %.10f \n",l,r,mid1,mid2);
//printf("%.10f\n",ans);
double a = s(mid1),b = s(mid2);
if(a <= b ){
ans = min(ans,a);
ans = min(ans,b);
r = mid2 - esp;
}else{
l = mid1 + esp;
ans = min(ans,b);
ans = min(ans,a);
}
}
printf("%.10f\n",ans);
}
int main()
{
int _;scanf("%d",&_);
while(_--) Slove();
return 0;
}