校内测试做到了,于是就把解题报告发出来。

简单回路

一个 \(n\times m\) 的方格纸,有 \(k\) 个障碍点。\(q\) 次询问,每次询问 \((x,y)\) ,问有多少条简单回路经过 \((x,y)-(x+1,y)\) 这条边。\(n\le 1000,m\le 6,k\le 100,q\le 10000\) 。

分析

场上 AC 了这题。

暴力的想法是每次询问都dp一次,到询问点的时候就强制有那个插头。由此就可以想到,如果可以快速转移完后面的所有格子,那么就可以只进行一次dp,经过一个格子之后就把含有这个插头的状态都快速转移一下,就可以直接预处理出每个 \((x,y)\) 的答案了。

因此,我们只需要求出 p[x][y][s] 数组表示 \((x,y)\) 这个位置状态为 \(s\) ,最后对答案的贡献系数。这是可以反过来转移求的。

因此总复杂度为 \(O(nm|s|)\) 。

代码

场上我的写法是一行行来做,所以复杂度为 \(O(nm|s|^2)\) ,也是可以过的。这是场上的代码 。

#include<bits/stdc++.h>
#define M(x) memset(x,0,(sizeof x[0])*maxs)
using namespace std;
typedef long long giant;
inline char nchar() {
static const int bufl=1<<20;
static char buf[bufl],*a,*b;
return a==b && (b=(a=buf)+fread(buf,1,bufl,stdin),a==b)?EOF:*a++;
}
inline int read() {
int x=0,f=1;
char c=nchar();
for (;!isdigit(c);c=nchar()) if (c=='-') f=-1;
for (;isdigit(c);c=nchar()) x=x*10+c-'0';
return f>0?x:-x;
}
const int maxn=1e3+5;
const int q=1e9+7;
const int maxs=200;
const int maxv=1<<16|1;
const int maxm=8;
inline int Plus(int x,int y) {return (x+=y)>=q?x-q:x;}
inline void Pe(int &x,int y) {x=Plus(x,y);}
inline int Multi(int x,int y) {return (giant)x*y%q;}
inline void Me(int &x,int y) {x=Multi(x,y);}
inline int get(int x,int p) {return (x>>(p<<1))&3;}
inline int mod(int x,int p,int d) {return (x&(~(3<<(p<<1))))+(d<<(p<<1));}
bool no[maxn][maxm];
int ans[maxn][maxm],stat[maxs],n,m,all=0,id[maxv],mat[maxs][maxm],ids=0,blo;
int tra[maxn][maxs],ader,to[maxs],F[2][maxs],*f=F[0],*g=F[1]; // to : how much transite to s
void dec(int x) {
for (int i=1;i<=m+1;++i) printf("%d ",get(x,i));
puts("");
}
inline void match(int x,int mt[]) {
static int sta[maxm];
int top=0;
for (int i=1;i<=m+1;++i) {
const int d=get(x,i);
if (d==1) sta[++top]=i; else if (d==2) {
int y=sta[top--];
mt[y]=i,mt[i]=y;
}
}
}
inline bool ok(int x) {
int cnt=0;
for (int i=1;i<=m+1;++i) {
const int d=get(x,i);
if (d==1) ++cnt; else if (d==2) --cnt;
if (cnt<0) return false;
}
return cnt==0;
}
void dfs(int now,int x) {
if (now>m+1) {
if (ok(x)) {
stat[id[x]=++ids]=x;
match(x,mat[ids]);
}
return;
}
for (int i=0;i<3;++i) dfs(now+1,mod(x,now,i));
}
void predp(int row,int st) {
M(f),M(g);
f[st]=1;
for (int j=1;j<=m;++j) {
swap(f,g),M(f);
for (int s=1;s<=ids;++s) if (g[s]) {
const int &d=stat[s],&w=g[s],x=get(d,j),y=get(d,j+1),c=mod(mod(d,j,0),j+1,0),*mt=mat[s];
if (no[row][j]) {
if (x==0 && y==0) Pe(f[id[d]],w);
continue;
}
if (x==0 && y==0) {
Pe(f[id[d]],w);
Pe(f[id[mod(mod(c,j,1),j+1,2)]],w);
} else if (x==0 || y==0) {
Pe(f[id[mod(c,j,x+y)]],w);
Pe(f[id[mod(c,j+1,x+y)]],w);
} else if (x==1 && y==1) {
Pe(f[id[mod(c,mt[j+1],1)]],w);
} else if (x==2 && y==2) {
Pe(f[id[mod(c,mt[j],2)]],w);
} else if (x==1 && y==2) {
if (!c) Pe(ader,w);
} else if (x==2 && y==1) {
Pe(f[id[c]],w);
}
}
}
for (int s=1;s<=ids;++s) if (get(stat[s],m+1)==0 && f[s]) Pe(to[id[stat[s]<<2]],f[s]);
}
void prepro() {
dfs(1,0);
for (int i=n;i;--i) {
for (int d=1;d<=ids;++d) if (get(stat[d],1)==0) {
ader=0;
memset(to,0,sizeof to);
predp(i,d);
tra[i][d]=ader;
for (int j=1;j<=ids;++j) if (to[j]) Pe(tra[i][d],Multi(to[j],tra[i+1][j]));
}
}
}
void work() {
M(f),M(g);
f[id[0]]=1;
for (int i=1;i<=n;++i) {
swap(f,g),M(f);
for (int s=1;s<=ids;++s) if (g[s]) {
const int &d=stat[s],&w=g[s];
if (get(d,m+1)==0) Pe(f[id[d<<2]],w);
}
for (int s=1;s<=ids;++s) if (f[s]) {
int tmp=Multi(f[s],tra[i][s]);
for (int j=2;j<=m+1;++j) if (get(stat[s],j)) Pe(ans[i-1][j-1],tmp);
}
for (int j=1;j<=m;++j) {
swap(f,g),M(f);
for (int s=1;s<=ids;++s) if (g[s]) {
const int &d=stat[s],&w=g[s],x=get(d,j),y=get(d,j+1),c=mod(mod(d,j,0),j+1,0),*mt=mat[s];
if (no[i][j]) {
if (x==0 && y==0) Pe(f[id[d]],w);
continue;
}
if (x==0 && y==0) {
Pe(f[id[mod(mod(c,j,1),j+1,2)]],w);
Pe(f[id[d]],w);
} else if (x==0 || y==0) {
Pe(f[id[mod(c,j,x+y)]],w);
Pe(f[id[mod(c,j+1,x+y)]],w);
} else if (x==1 && y==1) {
Pe(f[id[mod(c,mt[j+1],1)]],w);
} else if (x==2 && y==2) {
Pe(f[id[mod(c,mt[j],2)]],w);
} else if (x==2 && y==1) {
Pe(f[id[c]],w);
} // we don't process (x=1,y=2) since this will be add to answer on the next row
}
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
n=read(),m=read(),blo=read();
for (int i=1;i<=blo;++i) {
int x=read(),y=read();
no[x][y]=true;
}
prepro();
work();
int req=read();
while (req--) {
int x=read(),y=read();
printf("%d\n",ans[x][y]);
}
return 0;
}

卡常数

空间中有 \(n\) 个点,有两种操作:

  • 询问 \((x,y,z,r)\) ,问空间中哪个点在以 \((x,y,z)\) 为球心,\(r\) 为半径的球面上。保证答案唯一。
  • 修改 \((i,x,y,z)\) ,把 \(i\) 号点的坐标改为 \((x,y,z)\) 。

询问有加密。初始时 last=0.1 ,给出两个值 \(a,b (0\le b<a<5)\),对于每次询问的 \((x,y,z,r)\) 或 \((i,x,y,z)\) ,设被加密的值为 \(x\) ,那么给出的值为 \(f(last*x+1)\) ,其中 \(f(x)=ax-b\sin x\) 。

所有坐标随机。

\(n,m\le 65536\) 。

分析

从未见过如此奇怪的加密方式,要二分答案才能得到原值。

大部分人的做法是 KDTree 。

题解做法很神秘,启发性很大。一般的加密是为了强制在线,而有时候这种加密却可以帮助我们直接求出答案!

主要是利用了 \(i\in \mathbb Z,i\in [1,n]\) 的性质。稍微看了一下,感觉复杂度有点小问题,并没有仔细研究。

矩阵变换

有一个 \(n\times m\) 的矩阵,满足:

  • \(m>n\)
  • 每行 \([1,n]\) 出现恰好一次,其他位置均为 0
  • 每列 \([1,n]\) 每个数最多出现一次

现在要在每行中选出一个数 \(x\) ,并把这个数后面的所有位置都变为 \(x\) 。要求是保持第三个条件。

\(n,m\le 400,T\le 50\)

分析

这题很妙啊!

可以发现,每行选出的数 \(b_i\) 一定是 \(n\) 的一个排列。也就是说,这建立了一个 行 到 数 的匹配。

什么条件下第三个条件不满足呢?

若令行喜欢靠前的数,数喜欢令它靠后的行,那么这其实就是一个稳定婚姻问题。依次选择即可。

复杂度为 \(O(nm)\) 。

代码

#include<bits/stdc++.h>
#define M(x) memset(x,0,sizeof x)
using namespace std;
inline char nchar() {
static const int bufl=1<<20;
static char buf[bufl],*a,*b;
return a==b && (b=(a=buf)+fread(buf,1,bufl,stdin),a==b)?EOF:*a++;
}
inline int read() {
int x=0,f=1;
char c=nchar();
for (;!isdigit(c);c=nchar()) if (c=='-') f=-1;
for (;isdigit(c);c=nchar()) x=x*10+c-'0';
return x*f;
}
const int maxn=201,maxm=401;
int a[maxn][maxm],n,m,st[maxn],num[maxn],b[maxn],wh[maxn][maxn],sta[maxn],top;
void work() {
n=read(),m=read();
for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) wh[i][a[i][j]=read()]=j;
fill(st+1,st+n+1,1);
for (int i=1;i<=n;++i) sta[i]=i;
M(num),M(b),top=n;
while (top) {
int x=sta[top];
for (int &i=st[x];i<=m;++i) if (a[x][i]) {
int &v=a[x][i];
if (!num[v] || wh[num[v]][v]<i) {
if (num[v]) b[num[v]]=0,sta[top]=num[v]; else --top;
num[v]=x,b[x]=v,++i;
break;
}
}
}
for (int i=1;i<=n;++i) printf("%d%c",b[i]," \n"[i==n]);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
for (int T=read();T--;) work();
return 0;
}

清华集训2015-Day 2的更多相关文章

  1. 清华集训2015 V

    #164. [清华集训2015]V http://uoj.ac/problem/164 统计 描述 提交 自定义测试 Picks博士观察完金星凌日后,设计了一个复杂的电阻器.为了简化题目,题目中的常数 ...

  2. 「清华集训2015」V

    「清华集训2015」V 题目大意: 你有一个序列,你需要支持区间加一个数并对 \(0\) 取 \(\max\),区间赋值,查询单点的值以及单点历史最大值. 解题思路: 观察发现,每一种修改操作都可以用 ...

  3. uoj164. 【清华集训2015】V 统计

    坑爹题面:http://uoj.ac/problem/164 正常题面: 对于一个序列支持下列5个操作: 1.区间加x 2.区间减x并与0取max 3.区间覆盖 4.单点查询 5.单点历史最大值查询 ...

  4. UOJ #164. 【清华集训2015】V | 线段树

    题目链接 UOJ #164 题解 首先,这道题有三种询问:区间加.区间减(减完对\(0\)取\(\max\)).区间修改. 可以用一种标记来表示--标记\((a, b)\)表示把原来的值加上\(a\) ...

  5. uoj#158. 【清华集训2015】静态仙人掌

    http://uoj.ac/problem/158 预处理dfs序,询问转为区间1的个数,用可持久化bitset预处理出所有可能的修改对应哪些位置,然后用一个bitset维护当前每个点的状态,修改时可 ...

  6. [清华集训2015 Day2]矩阵变换-[稳定婚姻模型]

    Description 给出一个N行M列的矩阵,保证满足以下性质: M>N. 矩阵中每个数都是 [0,N]中的自然数. 每行中, [1,N]中每个自然数刚好出现一次,其余的都是0. 每列中,[1 ...

  7. [清华集训2015 Day1]主旋律-[状压dp+容斥]

    Description Solution f[i]表示状态i所代表的点构成的强连通图方案数. g[i]表示状态i所代表的的点形成奇数个强连通图的方案数-偶数个强连通图的方案数. g是用来容斥的. 先用 ...

  8. [清华集训2015 Day1]玛里苟斯-[线性基]

    Description Solution 考虑k=1的情况.假设所有数中,第i位为1的数的个数为x,则最后所有的子集异或结果中,第i位为1的个数为$(C_{k}^{1}+C_{k}^{3}+...)$ ...

  9. LOJ 164 【清华集训2015】V——线段树维护历史最值

    题目:http://uoj.ac/problem/164 把操作改成形如 ( a,b ) 表示加上 a 之后对 b 取 max 的意思. 每个点维护当前的 a , b ,还有历史最大的 a , b 即 ...

  10. 2018.07.28 uoj#164. 【清华集训2015】V(线段树)

    传送门 线段树好题. 要求支持的操作: 1.区间变成max(xi−a,0)" role="presentation" style="position: rela ...

随机推荐

  1. 菜鸟vimer成长记——第2.0章、模式初探

    首先,其他的文本编辑器只有一种模式,就是插入模式.而vim一下子颠覆了我们的世界观——有好多模式.这个是思维上的切换,很难也很重要!!! 其次,Vim 提供一个区分模式的用户界面.也就是说在不同的模式 ...

  2. Docker与CI持续集成/CD(转)

    背景 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制,相互之间不会 ...

  3. java并发编程——并发容器

    概述 java cocurrent包提供了很多并发容器,在提供并发控制的前提下,通过优化,提升性能.本文主要讨论常见的并发容器的实现机制和绝妙之处,但并不会对所有实现细节面面俱到. 为什么JUC需要提 ...

  4. pygrib学习

    pygrib-2.0.3/docs/index.html 导入pygrib模块 >>> import pygrib 打开grib文件,获取grib消息迭代器 >>> ...

  5. Qt-网易云音乐界面实现-5 收藏列表,播放列表实现 QListWidget QTableWidget

    先上目前完成的内容吧,发现后面越写越多.在看看点击量,心凉凉. 完成了左侧的导航列表,还有就是右下角的播放列表. //创建的歌单 my_Create_Music_List = new QListWid ...

  6. centos7 安装jenkenis

    安装Java 看到当前系统Java版本的命令: java -version 如果显示Java版本号,说明已经正确安装,如果显示没有该命令,需要安装Java: sudo yum install java ...

  7. php从入门到放弃系列-03.php函数和面向对象

    php从入门到放弃系列-03.php函数和面向对象 一.函数 php真正的威力源自它的函数,内置了1000个函数,可以参考PHP 参考手册. 自定义函数: function functionName( ...

  8. HPUX系统启动后主机名为unknown的解决办法

    HPUX系统启动完成后,主机名为unknown,查看/etc/rc.log出现如下报错:   unknown:[/]grep -i error /etc/rc.log /sbin/rc1.d/S320 ...

  9. Java调用XML的方法:DocumentBuilderFactory

    (1)首先得到:得到 DOM 解析器的工厂实例 DocumentBuilderFactory domfac=DocumentBuilderFactory.newInstance(); (2)然后从 D ...

  10. css3学习笔记一

    首先界面是二维的但也可以有三维的效果.先了解浏览器兼容性问题,火狐加前缀(-moz-)IE加(-MF-)谷歌加(-webkit),简单介绍css3的几个属性. 对于背景来说如果是单纯着一种颜色可以会单 ...