A

  只要打个表就能发现,1,6,8,9的所有排列就可以产生0~6的余数了...

  所以...走不下去的时候一定要打表...

  

 #define rep(i,n) for(int i=0 ; i<(n) ; i++)
#define mid ((l+r)>>1)
#define ls ((rt<<1))
#define rs ((rt<<1)+1)
#define maxn 1000100
char s[maxn];
string s2,f[];
int n,cnt[],m[]={,,,};
int getr(string t){
int r=;
rep(i,(int)t.size()){
int cur=t[i]-'';
r = (r*+cur)%;
}
// cout<<"string="<<t<<" r="<<r<<endl;
return r;
}
bool vis[];
void dfs(int step,string cur){
if (step==){
f[getr(cur)]=cur;
return;
}
// cout<<cur<<endl;
for (int i= ; i< ; i++ ) if (!vis[m[i]]){
vis[m[i]]=;
dfs(step+,cur+(char)(m[i]+''));
vis[m[i]]=;
}
}
int main(){
// freopen("test","r",stdin);
dfs(,(string)"");
scanf("%s",s);
n = strlen(s);
rep(i,n) cnt[s[i]-'']++;
rep(i,) cnt[m[i]]--;
s2 = "";
for (int i= ; i<= ; i++ ){
rep(j,cnt[i]) s2 += (char)(i+'');
}
int len = n-s2.size()-cnt[];
string s1 = s2;
rep(i,len) s1 += '';
int r = getr(s1);
s2 += f[(-r)%];
rep(i,cnt[]) s2 += '';
getr(s2);
cout<<s2<<endl;
return ;
}

B

  首先,想象一下,找到最大的矩形,可以看作在一些右端点对齐的线段中找到最大的矩形,然后枚举列就可以了,

  然后注意到"能重排row"这个条件,把所有线段按长度排序,扫一遍就能更新出最大,这个复杂度是 O(n*n*logn)的,

  最后,规模只有5000,排序可以用O(n)的基数排序,复杂度O(n*n).

 #include <map>
#include <ctime>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long llong;
#define rep(i,n) for(int i=0 ; i<(n) ; i++)
#define mid ((l+r)>>1)
#define ls ((rt<<1))
#define rs ((rt<<1)+1)
#define maxn 5001
int n,m,h[maxn],idx[maxn];
char g[maxn][maxn];
bool cmp(int x,int y){return x>y;}
int main(){
// freopen("test","r",stdin);
scanf("%d%d",&n,&m);
int area=;
rep(r,n) scanf("%s",g[r]);
vector<int>rcd;
rep(c,m){
// printf("add col:%d\n",c);
rep(r,n) {
h[r]=(g[r][c]=='')?h[r]+:;
// printf("g[%d][%d]=%d h[%d]=%d \n",r,c,g[r][c],r,h[r]);
}
rcd.clear();
rep(r,n) if(h[r]) rcd.push_back(h[r]);
sort(rcd.begin(),rcd.end(),cmp);
rep(i,(int)rcd.size()) area=max(area,rcd[i]*(i+));
}
printf("%d\n",area);
return ;
}

C

  本来以为是一道插头dp之类的...但是分析可以发现:

  1.特殊点<=8,可以状压;

  2.每走一步,可以确定当前轮廓中有哪些特殊点(根据题面给出的算法);

  于是可以转化为一个最短路问题:

  dist[i][j][mask], 到达(i,j)点的状态为mask时的最大价值,

  为了合法,最后答案的mask中代表'B'的位为0.

  总复杂度O(n*m*28*4*8)

 typedef long long llong;
#define rep(i,n) for(int i=0 ; i<(n) ; i++)
#define mid ((l+r)>>1)
#define ls ((rt<<1))
#define rs ((rt<<1)+1)
#define maxn 21
#define MASK (1<<8)
char g[maxn][maxn];
int n,m,id[maxn][maxn],cv,cb,var[MASK],
dr[]={,,-,},
dc[]={,,,-},
d[maxn][maxn][MASK];
bool inq[maxn][maxn][MASK];
struct node{
int r,c,msk;
};queue<node> q;
vector<node> b;
void input(){
scanf("%d%d",&n,&m);
rep(i,n) scanf("%s",g[i]);
memset(id,-,sizeof(id));
rep(i,n) rep(j,m) if (isdigit(g[i][j]))
id[i][j]=g[i][j]-'',cv++;
rep(i,n) rep(j,m) if (g[i][j]=='B')
id[i][j]=cv+(cb++);
rep(i,n) rep(j,m) {
if (g[i][j]=='B')
b.push_back((node){i,j,(<<id[i][j]>>cv)});
if (isdigit(g[i][j]))
b.push_back((node){i,j,(<<id[i][j]<<cb)});
}
rep(i,cv) scanf("%d",&var[<<i]);
}
int lowbit(int x) {return x&(-x);}
void pretreat(){
rep(i,MASK) if (i) var[i]=var[i-lowbit(i)]+var[lowbit(i)];
}
bool invalid(node cur){
if (cur.r<||cur.r>=n||cur.c<||cur.c>=m) return true;
if (id[cur.r][cur.c]!=-) return true;
if (g[cur.r][cur.c]=='#') return true;
return false;
}
void updata(node nxt,int x){
if (d[nxt.r][nxt.c][nxt.msk]==- || d[nxt.r][nxt.c][nxt.msk]>x){
d[nxt.r][nxt.c][nxt.msk]=x;
if (!inq[nxt.r][nxt.c][nxt.msk]){
inq[nxt.r][nxt.c][nxt.msk]=;
q.push(nxt);
}
}
}
int bfs(){
memset(d,-,sizeof(d));
memset(inq,,sizeof(inq));
node cur,nxt;
int ans=;
rep(i,n) rep(j,m) if (g[i][j]=='S'){
q.push((node){i,j,});
d[i][j][]=;
inq[i][j][]=;
break;
}
while (!q.empty()){
cur = q.front(); q.pop();
inq[cur.r][cur.c][cur.msk]=;
if (g[cur.r][cur.c]=='S' && ((cur.msk&((<<cb)-))==) )
ans = max(ans,var[cur.msk>>cb]-d[cur.r][cur.c][cur.msk]);
rep(i,){
nxt.r = cur.r+dr[i];
nxt.c = cur.c+dc[i];
if (invalid(nxt)) continue;
if (i&){
nxt.msk=cur.msk;
rep(j,(int)b.size()) {
if (i==) {
if (b[j].r>nxt.r && b[j].c==nxt.c) nxt.msk^=b[j].msk;
} else {
if (b[j].r>cur.r && b[j].c==cur.c) nxt.msk^=b[j].msk;
}
}
}else nxt.msk = cur.msk;
updata(nxt,d[cur.r][cur.c][cur.msk]+);
}
}
return ans;
}
int main(){
input();
pretreat();
printf("%d\n",bfs());
return ;
}

  trick:

  判断点是否在轮廓中时,只要考虑一个方向的射线;

  同一个点向相反的方向走,在mask中更新的点不一样.

D

  合并树:

  以col为关键字造平衡树,回答在u上询问时,先递归回答它所有子树的询问;

  然后合并子树,更新k值,因为每加入一个节点,k变化一次,所以均摊复杂度O(n),合并树的总复杂度O(nlogn);

  

  朴素做法:

  共用2个数组记录颜色频率feq和k值,回答u询问时,先递归回答它子树询问,

  回溯时删除之前递归产生的统计,然后递归到下一个子树...

  for x in e[u]:

    dfs(x),del(x);

  最后加入所有子树,回答u上的询问:

  for x in e[u]:

    add(x);

  这样的做法是O(n2)的.

  优化:

  最大的子树不进行del和add操作,可以优化为O(nlogn).

  分析:

  对于节点v,它被del时的祖先为u,那么size[u]>=2*size[v],所以v最多有logn个这样的祖先u,即它最多被执行longn次del操作,

  add操作比del操作多一次.

  

 #define rep(i,n) for(int i=0 ; i<(n) ; i++ )
#define ls ((rt)<<1)
#define rs (((rt)<<1)+1)
#define mid ((l+r)>>1)
#define maxn 100100
vector<int> e[maxn],q[maxn];
int qk[maxn],sz[maxn],n,m,col[maxn],cnt[maxn],f[maxn],ans[maxn]; void add(int x,int fa){
cnt[col[x]]++;
f[cnt[col[x]]]++;
rep(i,(int)e[x].size()) if(e[x][i]!=fa)
add(e[x][i],x);
}
void del(int x,int fa){
f[cnt[col[x]]]--;
cnt[col[x]]--;
rep(i,(int)e[x].size()) if(e[x][i]!=fa){
del(e[x][i],x);
}
}
void dfs(int cur,int fa){
int big=-,idx=-;
rep(i,(int)e[cur].size()) if(e[cur][i]!=fa){
if (sz[e[cur][i]]>big){
big = sz[e[cur][i]];
idx = i;
}
}
rep(i,(int)e[cur].size()) if(e[cur][i]!=fa){
if (i==idx) continue;
dfs(e[cur][i],cur);
del(e[cur][i],cur);
}
if (idx!=-) dfs(e[cur][idx],cur);
cnt[col[cur]]++;
f[cnt[col[cur]]]++;
rep(i,(int)e[cur].size()) if(e[cur][i]!=fa){
if (i==idx) continue;
add(e[cur][i],cur);
}
rep(i,(int)q[cur].size()){
int id = q[cur][i];
int k = qk[id];
ans[id] = f[k];
}
}
void initsz(int x,int fa){
sz[x]=;
rep(i,(int)e[x].size()) if(e[x][i]!=fa){
initsz(e[x][i],x);
sz[x] += sz[e[x][i]];
}
}
int main(){
// freopen("test.txt","r",stdin);
scanf("%d%d",&n,&m);
for (int i= ; i<=n ; i++ ) scanf("%d",&col[i]);
for (int i= ; i<n ; i++ ){
int u,v;
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
initsz(,);
rep(i,m){
int k,x;
scanf("%d%d",&x,&k);
q[x].push_back(i);
qk[i]=k;
}
dfs(,);
rep(i,m) printf("%d\n",ans[i]);
return ;
}

E

  第一步可以把问题转化为:求用不超过cntb个的黑点覆盖整个树的最小代价,在本来是黑点处放黑点代价为0,在红点处放黑点代价为1;

  然后当假设总共用了i个黑点,问题貌似就能表示为一个容量为i的背包了:

  dp[u][i] 表示u为根的子树用i个黑点覆盖的最小代价;

  不过还有一个问题:u被覆盖的情况很复杂,可能覆盖点来自u这颗子树的外面.

  于是需要再加以为来描述覆盖u的点:

  dp[u][i][w] 表示u为根的子树,用i个黑点覆盖,此外u已经被w覆盖 的最小代价.

  最后我们的答案就是 best[0][i] = min{dp[0][i][w]}  (0<i<=cntb , 0<=w<n);

  

 using namespace std;
#define rep(i,n) for(int i=0 ; i<(n) ; i++ )
#define ls ((rt)<<1)
#define rs (((rt)<<1)+1)
#define mid ((l+r)>>1)
#define maxn 501
#define INF 10001
struct node{
int v,w;
};vector<node> e[maxn];
short dp[maxn][maxn][maxn];
int dp2[maxn][maxn],best[maxn][maxn],
col[maxn],dist[maxn][maxn],n,x,sz[maxn]; void initdist(int u,int fa,int rt,int d) {
if (d>=x+) d=x+;
dist[rt][u]=d;
rep (i,(int)e[u].size()) {
if (e[u][i].v==fa) continue;
initdist(e[u][i].v,u,rt,d+e[u][i].w);
}
} void dfs(int u,int fa) {
int chd[maxn],nch=;
sz[u]=;
rep (i,(int)e[u].size()) {
if (e[u][i].v==fa) continue;
dfs(e[u][i].v,u);
chd[nch++]=e[u][i].v;
sz[u] += sz[e[u][i].v];
}
// printf("*********************************\n");
// printf("u:%d\n",u);
rep (w,n) {
if (dist[u][w]>x) continue;
if (nch) {
int tot=,c,c1;
c = chd[];
tot += sz[c];
rep (i,tot)
dp2[c][i] = min((int)dp[c][i][w],best[c][i]);
for (int i= ; i<nch- ; i++ ) {
c = chd[i];
c1 = chd[i+];
rep (j,tot+sz[c1]+) dp2[c1][j] = INF;
rep (j,tot) rep(k,sz[c1]+) {
if (k<sz[c1]) dp2[c1][j+k] = min(dp2[c1][j+k],dp2[c][j]+dp[c1][k][w]);
dp2[c1][j+k] = min(dp2[c1][j+k],dp2[c][j]+best[c1][k]);
}
tot += sz[c1];
}
}
// printf("w:%d\n",w);
// rep (i,nch) rep (j,sz[u]+1) printf("dp2[%d][%d]=%d\n",chd[i],j,dp2[chd[i]][j]);
rep (i,sz[u]) {
if (nch) dp[u][i][w] = dp2[chd[nch-]][i];
else dp[u][i][w] = ;
// printf("dp[%d][%d][%d]=%d\n",u,i,w,dp[u][i][w]);
}
rep (i,sz[u]) {
best[u][i+] = min(best[u][i+],dp[u][i][w]+(col[w]==));
}
}
// rep (i,sz[u]+1) printf("best[%d][%d]=%d\n",u,i,best[u][i]);
// printf("*********************************\n");
} void solv() {
rep (i,n) initdist(i,-,i,);
rep (i,maxn) rep (j,maxn) rep (k,maxn) dp[i][j][k]=INF;
rep (i,maxn) rep (j,maxn) dp2[i][j]=INF,best[i][j]=INF;
dfs(,-);
int ans = INF;
int cntb=;
rep (i,n) cntb += col[i];
rep (i,cntb+) ans = min(ans,best[][i]);
printf("%d\n",ans==INF?-:ans);
} int main(){
// freopen("test.txt","r",stdin);
scanf("%d%d",&n,&x);
rep (i,n) scanf("%d",&col[i]);
rep (i,n-) {
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
u--, v--;
e[u].push_back((node){v,w});
e[v].push_back((node){u,w});
}
solv();
return ;
}

  背包部分的复杂度:

  看起来似乎每次dfs,背包部分的复杂度是o(n^2)的,但实际整个过程中,对于每个w,每对lca恰好访问一次,所以均摊复杂度是 O(n2),总复杂度O(n3)

(p.s 最开始仿照rank1的写法dp,然后发现dp2的下标可以用直接用节点编号就不用每次dfs都初始化1次,于是后面按自己想法写...

  最后发现答案偏小了,呆看了一阵发现,枚举w的时候dp2也需要初始化...)

这套题的D,E还蛮考复杂度分析的,涨姿势了...

  

Codeforce 221 div1的更多相关文章

  1. Codeforce 222 div1

    A 假设只有一个连通块,任选一个点入队,按bfs/dfs序删除即可. trick: 要考虑有多个连通块的情况,不一定无解. #define rep(i,n) for(int i=0 ; i<(n ...

  2. Codeforce 219 div1

    B 4D"部分和"问题,相当于2D部分和的拓展,我是分解成2D部分和做的: f[x1][y1][x2][y2]=true/false 表示 左上(x1,y1) 右下(x2,y2)的 ...

  3. Codeforce 215 div1

    C 把每个qi看成点,则问题转化为:求一个最大的k,遍历k个点的完全图需要的最小步数+1不超过n, (这里+1的原因是把起点加进去) 讨论k的奇偶: k为奇数,每个点度数为偶数,这是一个欧拉回路,步数 ...

  4. css小随笔

    一.什么是CSS W3C标准中,倡导有3:其一为内容与表现分离,其二为内容与行为分离,其三为内容结构的语义化.其倡导中第一条的"表现"指的便可以说是CSS.CSS全称Cascadi ...

  5. 学起来 —— CSS 入门基础

    Hello,大家好! 小女来更博啦!CSS福利送上~~~ 首先给大家介绍一下CSS到底是什么? 一.CSS概念 W3C规范中,要求有三条:一 为"两个分离",二 为语言遵循语义化, ...

  6. ACM思维题训练 Section A

    题目地址: 选题为入门的Codeforce div2/div1的C题和D题. 题解: A:CF思维联系–CodeForces -214C (拓扑排序+思维+贪心) B:CF–思维练习-- CodeFo ...

  7. Codeforce Round #221 Div2

    每次的CF都是一把辛酸泪! 什么时候能打破这局面,昨天做着睡着了! 有时候有的题目也就差一线! 哎,! A:杠杆原理! B:算最后负的和! B:没弄出来当时就脑短路... C:事后写了个n*log(n ...

  8. Android Weekly Notes Issue #221

    Android Weekly Issue #221 September 4th, 2016 Android Weekly Issue #221 ARTICLES & TUTORIALS And ...

  9. CF#345 (Div1)

    论蒟蒻如何被cf虐 以下是身败名裂后的题解菌=========== Div1 A.Watchmen 有n个点,每个点有一个坐标.求曼哈顿距离=欧几里得距离的点对数量. 只需要统计x或y一样的点对数量. ...

随机推荐

  1. jquery中prop()方法和attr()方法的区别(转)

    jquery1.6中新加了一个方法prop(),一直没用过它,官方解释只有一句话:获取在匹配的元素集中的第一个元素的属性值. 官方例举的例子感觉和attr()差不多,也不知道有什么区别,既然有了pro ...

  2. mysql将一个库中表的某几个字段插入到另一个库中的表

    insert into dbname1.tablename1(filed1,filed2,filed3) select filed1,filed2,filed3from dbname2.tablena ...

  3. HashSet内存泄露

    import java.util.HashSet; import java.util.Set; public class PersonTest { public static void main(St ...

  4. Android(java)学习笔记252:ContentProvider使用之内容观察者01

    1. 内容观察者 不属于四大组件,只是内容提供者ContentProvider对应的小功能. 如果发现数据库内容变化了,就会立刻观察到. 下面是逻辑图:       当A应用中银行内部的数据发生变化的 ...

  5. FineUI页面级别的参数配置

    Theme: 控件主题,目前支持三种主题风格(blue/gray/access,默认值:blue) Language: 控件语言(en/zh_CN/zh_TW/...,默认值:zh_CN) FormM ...

  6. require(),include(),require_once()和include_once()之间的区别

    引用文件的方法有两种:require 及 include. require 的使用方法如 require("file.php"); .这个函数通常放在 PHP 程序的最前面,PHP ...

  7. Struts2 UI标签

    表单标签的共同属性(该属性只在没有使用 simple 主题时才可以使用) form 标签  用来呈现 HTML 语言中的表单元素 默认情况下, form 标签将被呈现为一个表格形式的 HTML 表单. ...

  8. 【C#编程基础学习笔记】6---变量的命名

    2013/7/24 技术qq交流群:JavaDream:251572072  教程下载,在线交流:创梦IT社区:www.credream.com [C#编程基础学习笔记]6---变量的命名 ----- ...

  9. windows Server 2003修改远程连接限制

    调整最大远程连接数: 1.开始->控制面板->添加或删除程序->添加/删除windows组件->选择“终端服务器”进行安装. 2.开始->运行->gpedit.ms ...

  10. centos6.2下安装星际译王stardict3.0

    星际译王是一个Linux下很好的翻译软件. 我的系统是centos6.2 32位版.本来在http://code.google.com/p/stardict-3/downloads/list 上下的源 ...