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. C盘满了

      今天电脑提示说C盘磁盘满了,于是开始做磁盘清理 右击C盘,点管理. 点击磁盘清理,勾选中临时文件.下载.回收站.缩略图,然后点击清理系统文件. 再去查看C盘仍然没有多大变化,于是挨个翻看C盘到底哪 ...

  2. kernel32.dll函数简介

    kernel32.dll是非常重要的32位动态链接库文件,属于内核级文件.它控制着系统的内存管理.数据的输入输出操作和中断处理,当Windows启动时,kernel32.dll就驻留在内存中特定的写保 ...

  3. 普通java项目打成jar包,引入第三方jar .

    ja方法1 .  MANIFEST.MF 中添加  Class-Path . 1.  项目src目录下创建  META-INF/MANIFEST.MF 文件.文件内容 Manifest-Version ...

  4. 封装python代码,避免被轻易反编译

    可使用Cython对python代码进行封装,封装成.pyd库,大致流程可参考: cython打包py成pyd,pyinstaller打包uvicorn服务过程记录_Bolly_He的博客-CSDN博 ...

  5. 访问修饰符 protected(s)

    protected 受保护的:可以在当前类的内部以及该类的子类中可以访问. using System; using System.Collections.Generic; using System.L ...

  6. SHR之员工合同解除

    员工合同解除HRContractInfoFacadeControllerBean 这块的意思的源码可以自行翻阅该源码. 调用员工的实现这个合同自动解除 String sql="select ...

  7. linux 部署python 系统服务管理命令 yum源设置 linux定时任务 python在linux的虚拟环境安装以及使用

    安装python3 三种方式 ==linux下很多脚本默认都用python2, 所以不要把python3的执行文件改为python,因为linux里默认python就是运行python2版本 == y ...

  8. 在vue js中for循环使用

    在线免费图片压缩工具 前端技术站 1.for(let item of response.data.result) { 用item操作每一条数据. } item:定义的每一条的变量 response.d ...

  9. web server 接口调用测试

    1.新建工程 ,鼠标右击new 2.设置web server接口访问链接,然后下一步 生成代码 3.生成客户端代码 4.创建测试类 调用服务

  10. Linux:服务器(CentOS)搭建FTP服务

    Vsftpd(very secure FTP deamon)是众多Linux发行版中默认的FTP服务器.本文以CentOS 8(腾讯云)服务器为例,使用vsftpd搭建Linux云服务器的FTP服务器 ...