CF1408
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的更多相关文章
随机推荐
- 浏览器中通过js获取用户语言环境方法
用户语言环境存在navigator对象中,不同浏览器分别通过如下方法获取用户浏览器语言.操作系统语言. IE6 IE7 IE8 Firefox Chrome Safari Opera naviga ...
- R7-7 调查电视节目受欢迎程度
R7-7 调查电视节目受欢迎程度 分数 15 全屏浏览题目 切换布局 作者 颜晖 单位 浙大城市学院 某电视台要调查观众对该台8个栏目(设相应栏目编号为1~8)的受欢迎情况,共调查了n位观众(1≤n≤ ...
- layui 关闭/打开新标签
setTimeout(function () { //关闭当前页面并跳转到课程列表 var topLayui = parent === self ? layui : top.layui; parent ...
- fiddler设置自动响应
使用fiddler 设置AutoResponder 1.auto responder:自动响应器,设置并开启后将把请求接口拦截并返回 2.enable rules:开启规则,开启后规则启用 3.unm ...
- vue cli 项目初始化配置
- Cascader 级联选择器 数据不回显
这次的问题原因主要是因为 数据存在于两张表 并且索引的字段不同 一个为id(int)一个为字符(string) 在做修改操作数据回显的时候会导致 后端返回的数组中一个为字符一个为bumber ...
- vue的双向绑定规则
vue提供了v-model双向绑定指令,用来辅助在不操作DOM的前提下,快速读取表单的数据 <!DOCTYPE html> <html lang="en"> ...
- Ubuntu 20.04 部署Prmoetheus+grafana+mysql+mysqld_exporter+node_exporter
Prometheus简介 Prometheus是一个功能强大的开源监控系统,可从您的服务中收集指标并将其存储在时间序列数据库中.它通过Grafana等工具提供多维数据模型,灵活的查询语言和多样化的可视 ...
- promethus+grafana监控
1.监控 MySQL (终端可以安装在任意主机,不一定按在mysql节点上,注:mysql版本需在5.5以上) I.首先在mysql中添加监控使用的用户: create user 'exp'@'%' ...
- Jmeter完整全套接口流程
根据实际项目,编写一套完整的接口流程 项目流程介绍: 借款流程需要调用的接口,依次为: 前置校验:主要通过手机号验证该用户是存量用户,若撞库,则不允许继续操作: 用户注册:通过手机号+身份证号进行注册 ...