CF1408

那个博客搭好遥遥无期。

A:

直接做就行了,我没智力还写 \(dp\) 。

#include<bits/stdc++.h>
using namespace std;
#define MAXN 110
int n;
int p[MAXN][3];
bool f[MAXN][3];
int pre[MAXN][3];
int ans[MAXN];
void work()
{
scanf("%d",&n);
for(int j = 0;j < 3;++j)for(int i = 1;i <= n;++i)scanf("%d",&p[i][j]);
for(int v = 0;v < 3;++v)
{
memset(f,0,sizeof(f));
f[1][v] = true;
for(int i = 2;i <= n;++i)
{
for(int y = 0;y < 3;++y)
{
for(int x = 0;x < 3;++x)
{
if(p[i - 1][x] != p[i][y] && f[i - 1][x])
{
f[i][y] = true;
pre[i][y] = x;
break;
}
}
}
}
bool tag = false;
for(int i = 0;i < 3;++i)
{
if(f[n][i] && p[n][i] != p[1][v])
{
for(int k = n,cur = i;k >= 1;--k)
{
ans[k] = p[k][cur];
cur = pre[k][cur];
}
for(int k = 1;k <= n;++k)printf("%d ",ans[k]);puts("");
tag = true;
break;
}
}
if(tag)break;
}
return;
}
int main()
{
int testcases;
scanf("%d",&testcases);
while(testcases--)work();
return 0;
}

B:

还挺有意思的,就是从左往右数如果颜色达到\(k\)了就把剩下的拿出去再一样做,统计颜色段数算一算。

#include<bits/stdc++.h>
using namespace std;
#define MAXN 110
int n,k;
int a[MAXN];
void work()
{
scanf("%d%d",&n,&k);
for(int i = 1;i <= n;++i)scanf("%d",&a[i]);
int cnt = 0;
for(int i = 1;i < n;++i)if(a[i] != a[i + 1])++cnt;
if(cnt == 0)puts("1");
else if(k == 1)puts("-1");
else
{
++cnt;
int ans = 0;
while(cnt > 0)
{
++ans;
cnt -= k;
if(cnt <= 0)break;
++cnt;
}
cout << ans << endl;
} return;
}
int main()
{
int testcases;
scanf("%d",&testcases);
while(testcases--)work();
return 0;
}

C:

算到每个位置两人的速度和时间,这样即可得知在哪段相遇,然后就能算了。

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
int n,l;
int a[MAXN];
double ta[MAXN],tb[MAXN];
int va[MAXN],vb[MAXN];
void work()
{
scanf("%d%d",&n,&l);
for(int i = 1;i <= n;++i)scanf("%d",&a[i]);
a[n + 1] = l;
ta[0] = 0;va[0] = 1;
for(int i = 1;i <= n + 1;++i)
{
va[i] = va[i - 1] + 1;
ta[i] = double(a[i] - a[i - 1]) / va[i - 1] + ta[i - 1];
}
tb[n + 1] = 0;vb[n + 1] = 1;
for(int i = n;i >= 0;--i)
{
vb[i] = vb[i + 1] + 1;
tb[i] = double(a[i + 1] - a[i]) / vb[i + 1] + tb[i + 1];
}
for(int i = 1;i <= n;++i)
{
if(fabs(ta[i] - tb[i]) <= 1e-6)
{
printf("%.20lf\n",ta[i]);
return;
}
}
int pos = -1;
for(int i = 0;i <= n;++i)
{
if(ta[i] <= tb[i] && ta[i + 1] >= tb[i + 1])
{
pos = i;
break;
}
}
printf("%.20lf\n",(a[pos + 1] - a[pos] + ta[pos] * va[pos] + tb[pos + 1] * vb[pos + 1]) / (va[pos] + vb[pos + 1]));
return;
}
int main()
{
int testcases;
scanf("%d",&testcases);
while(testcases--)work();
return 0;
}

D:

对每个向上走的长度记录 \(l[i]\) 表示要向右走多少才行,然后会发现可以前缀最大值做。

#include<bits/stdc++.h>
using namespace std;
int n,m;
#define MAXN 2010
#define INF 0x3f3f3f3f
int a[MAXN],b[MAXN],c[MAXN],d[MAXN];
struct move
{
int u,r;
}s[MAXN];
int up[1000010];
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i)scanf("%d%d",&a[i],&b[i]);
for(int i = 1;i <= m;++i)scanf("%d%d",&c[i],&d[i]);
for(int i = 1;i <= n;++i)
{
for(int j = 1;j <= m;++j)
{
if(c[j] >= a[i] && d[j] >= b[i])
{
up[c[j] - a[i]] = max(up[c[j] - a[i]],d[j] - b[i] + 1);
}
}
}
for(int i = 1000000;i >= 0;--i)
{
up[i] = max(up[i],up[i + 1]);
}
int ans = 0x3f3f3f3f;
for(int i = 0;i <= 1000001;++i)
{
ans = min(ans,i + up[i]);
}
cout << ans << endl;
return 0;
}

E:

把团内的每个点向团所代表的点连边,然后会发现没有 \(rainbow\) 等价于这个图没有环。

#include<bits/stdc++.h>
using namespace std;
int n,m;
#define MAXN 100010
int a[MAXN],b[MAXN];
namespace KRU
{
struct edge{int u,v,w;}e[MAXN << 1];
int edgenum = 0;
void add(int a,int b,int w){e[++edgenum] = (edge){a,b,w};return;}
bool cmp(edge a,edge b){return a.w > b.w;}
int f[MAXN << 1];
int find(int x){return (f[x] == x ? x : f[x] = find(f[x]));}
long long kruskal()
{
long long ans = 0;
sort(e + 1,e + 1 + edgenum,cmp);
for(int i = 1;i <= n + m;++i)f[i] = i;
for(int i = 1;i <= edgenum;++i)
{
int p = find(e[i].u),q = find(e[i].v);
if(p == q)continue;
ans += e[i].w;
f[p] = q;
}
return ans;
}
}
int main()
{
scanf("%d%d",&m,&n);
for(int i = 1;i <= m;++i)scanf("%d",&a[i]);
for(int i = 1;i <= n;++i)scanf("%d",&b[i]);
long long ans = 0;
for(int i = 1;i <= m;++i)
{
int s;scanf("%d",&s);
int v;
for(int k = 1;k <= s;++k)
{
scanf("%d",&v);
KRU::add(i + n,v,a[i] + b[v]);//cout << " : " << i << " " << v << " " << a[i] << " " << b[v] << " " << a[i] + b[v] << endl;
ans += a[i] + b[v];
}
}
ans -= KRU::kruskal();
cout << ans << endl;
return 0;
}

F:

发现可以分治让 \(2^n\) 长度的区间变成一个数,那么就对 \([1,l]\) 和 \([n-l+1,n]\) 都做一遍就行了。

#include<bits/stdc++.h>
using namespace std;
int n;
vector< pair<int,int> > ans;
void solve(int l,int r)
{
if(l == r)return;
int mid = (l + r) >> 1;
solve(l,mid);solve(mid + 1,r);
for(int i = l;i <= mid;++i)ans.push_back(make_pair(i,mid + 1 + i - l));
return;
}
int main()
{
cin >> n;
int l = 1;
while(l * 2 <= n)l = l * 2;
solve(1,l);solve(n - l + 1,n);
cout << ans.size() << endl;
for(int i = 0;i < ans.size();++i)printf("%d %d\n",ans[i].first,ans[i].second);
return 0;
}

G:

团内边小于团之间的边,一个团可以增加一,连接两个连通块就卷积,相当于树形 \(dp\) ,\(O(n^2)\) 。

#include<bits/stdc++.h>
using namespace std;
#define MOD 998244353
inline int read()
{
int res = 0;
char c = getchar();
while(!isdigit(c))c = getchar();
while(isdigit(c))
{
res = (res << 1) + (res << 3) + c - '0';
c = getchar();
}
return res;
}
int n;
#define MAXN 1510
struct edge
{
int u,v,w;
}es[MAXN * MAXN];
int en = 0;
int f[MAXN];
int ecnt[MAXN];
int siz[MAXN];
int find(int x){return (x == f[x] ? x : f[x] = find(f[x]));}
bool cmp(edge a,edge b){return a.w < b.w;}
int dp[MAXN][MAXN];
int g[MAXN];
void merge(int a,int b)
{
for(int i = 1;i <= siz[a] + siz[b];++i)g[i] = 0;
for(int i = 1;i <= siz[a];++i)
for(int j = 1;j <= siz[b];++j)
g[i + j] = (g[i + j] + 1ll * dp[a][i] * dp[b][j] % MOD) % MOD;
for(int i = 1;i <= siz[a] + siz[b];++i)dp[a][i] = g[i];
return;
}
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n;++i)f[i] = i,siz[i] = 1;
for(int i = 1;i <= n;++i)for(int j = 1;j <= n;++j)es[++en] = (edge){i,j,read()};
sort(es + 1,es + 1 + en,cmp);
for(int i = 1;i <= en;++i)
{
int p = find(es[i].u),q = find(es[i].v);
if(p == q)++ecnt[p];
else
{
if(siz[p] < siz[q])swap(p,q);
merge(p,q);
f[q] = p;
siz[p] += siz[q];
ecnt[p] += ecnt[q] + 1;
}
if(ecnt[p] == siz[p] * siz[p])dp[p][1] = 1;
}
int root = find(1);
for(int i = 1;i <= n;++i)printf("%d ",dp[root][i]);
return 0;
}

H:

设零的个数为 \(z\) ,则答案不超过 \(\lfloor\frac z2\rfloor\) ,那么将序列划为两半 \(L\) 和 \(R\) ,满足对于 \(x\in L\) 右边有大于 \(\lfloor\frac z2\rfloor\) 个 \(0\) ,\(R\) 同理,那么可以发现每种颜色只有 \(L\) 中最右边的和 \(R\) 中最左边的有用。那么可以网络流,\(S\) 连颜色,\(L\) 中每个点往左连,\(R\) 中每个点往右连,颜色连两个有用的点,零连 \(T\) ,分析一下,如果一个颜色不割,那么他的前缀零后缀零一定都被割了,那最后一定是割了前缀零,后缀零,还有不是包含在前缀后缀的,于是扫描线加线段树统计。

#include<bits/stdc++.h>
using namespace std;
int n;
#define MAXN 500010
int a[MAXN];
int cnt0;
struct match{int l,r;}ma[MAXN];
int sum0l[MAXN],sum0r[MAXN];
struct node
{
int lc,rc;
int minv,tag;
}t[MAXN << 1];
int ptr = 0;
int newnode(){return ++ptr;}
int root;
#define mid ((l + r) >> 1)
void build(int &rt,int l,int r)
{
rt = newnode();
if(l == r){t[rt].minv = sum0r[l] + n;return;}
build(t[rt].lc,l,mid);
build(t[rt].rc,mid + 1,r);
t[rt].minv = min(t[t[rt].lc].minv,t[t[rt].rc].minv);
return;
}
void pushdown(int rt)
{
t[t[rt].lc].minv += t[rt].tag;t[t[rt].lc].tag += t[rt].tag;
t[t[rt].rc].minv += t[rt].tag;t[t[rt].rc].tag += t[rt].tag;
t[rt].tag = 0;
return;
}
void add(int rt,int L,int R,int v,int l,int r)
{
if(L <= l && r <= R)
{
t[rt].minv += v;
t[rt].tag += v;
return;
}
pushdown(rt);
if(L <= mid)add(t[rt].lc,L,R,v,l,mid);
if(R > mid)add(t[rt].rc,L,R,v,mid + 1,r);
t[rt].minv = min(t[t[rt].lc].minv,t[t[rt].rc].minv);
return;
}
int query(int rt,int L,int R,int l,int r)
{
if(L <= l && r <= R)return t[rt].minv;
int res = 0x3f3f3f3f;
if(L <= mid)res = min(res,query(t[rt].lc,L,R,l,mid));
if(R > mid)res = min(res,query(t[rt].rc,L,R,mid + 1,r));
return res;
}
vector<int> seg[MAXN];
void work()
{
scanf("%d",&n);
for(int i = 1;i <= n;++i)scanf("%d",&a[i]);
cnt0 = 0;
for(int i = 1;i <= n;++i)cnt0 += (a[i] == 0);
int s = (cnt0 + 1) / 2;
for(int i = 1;i <= n;++i)ma[i].l = 0,ma[i].r = n + 1;
sum0l[0] = sum0r[n + 1] = 0;
for(int i = 1;i <= n;++i)sum0l[i] = sum0l[i - 1] + (a[i] == 0);
for(int i = n;i >= 1;--i)sum0r[i] = sum0r[i + 1] + (a[i] == 0);
int bor;
for(int i = 1,c0 = 0;i <= n;++i)
{
if(a[i] == 0)++c0;
if(c0 == s){bor = i;break;}
}
for(int i = bor;i >= 1;--i)if(a[i] && ma[a[i]].l == 0)ma[a[i]].l = i;
for(int i = bor;i <= n;++i)if(a[i] && ma[a[i]].r == n + 1)ma[a[i]].r = i;
for(int i = 0;i <= n + 1;++i)seg[i].clear();
for(int i = 1;i <= n;++i)seg[ma[i].l].push_back(ma[i].r);
ptr = 0;
build(root,bor,n + 1);
int ans = 0x3f3f3f3f;
for(int l = 0;l <= bor;++l)
{
for(vector<int>::iterator it = seg[l].begin();it != seg[l].end();++it)add(root,bor,*it,-1,bor,n + 1);
ans = min(ans,query(root,bor,n + 1,bor,n + 1) + sum0l[l]);
}
printf("%d\n",min(ans,cnt0 / 2));
for(int i = 1;i <= ptr;++i)t[i].lc = t[i].rc = t[i].minv = t[i].tag = 0;
return;
}
int main()
{
int testcases = 0;
scanf("%d",&testcases);
while(testcases--)work();
return 0;
}

I:

咕咕咕

CF1408的更多相关文章

随机推荐

  1. centos7.2下配置dhcp v4或v6服务

    1.centos7.2下配置dhcp v4或v6服务 安装dhcp-server centos7及以前版本的操作系统使用命令: yum install dhcp centos8使用命令: yum in ...

  2. 将excel按照某一列拆分成多个文件

    1.打开目标excel,按alt + f11键打开VBE窗口 2.选择插入->模块粘贴下面代码到编辑器中 Sub 保留表头拆分数据为若干新工作簿() Dim arr, d As Object, ...

  3. Finance财务软件(权限管理专题)

    我们支持按模块对用户授权 如上所示,我们对用户test进行授权.test登录系统后将看不到未授权的菜单:

  4. unity默认管线lightmap

    lightmap采样 https://blog.csdn.net/wodownload2/article/details/94431040

  5. HTML弹窗设计二

    <!DOCTYPE html><html> <head> <title>模态框弹出层.html</title> <meta http- ...

  6. .NET 7介绍及环境准备

    环境要求 VS2022 17.4+

  7. (面试题)面试官为啥总是让我们手撕call、apply、bind?

    引言 上一篇关于<面试官为啥总是喜欢问前端路由实现方式>的文章发布后,发现还是挺受欢迎的.这就给我造成了一定的困惑 之前花了很长时间,实现了一个自认为创意还不错的关于前端如何利用node+ ...

  8. ratel hook app

    目录 创建平头哥项目 创建一个基本的Android项目 手动创建一个平头哥项目(windows推荐) 通过模板的方式创建平头哥项目(windows不推荐) 插入第三方集成模块 RPC调用 RPC调用静 ...

  9. sql server 检测是否更新并输出更新的数据

    create table dbo.test1 (id int,name varchar(10))create table dbo.test2 (id int) insert into dbo.test ...

  10. 我眼中的Serverless

    https://cloud.tencent.com/document/product/583 摆脱服务器.存储等底层设备,只上传代码,由云服务器提供服务的触发,维护,调用.