2014 Multi-University Training Contest 3
官方解题报告http://blog.sina.com.cn/s/blog_a19ad7a10102uyiq.html
Wow! Such Sequence! http://acm.hdu.edu.cn/showproblem.php?pid=4893
线段树,比赛时写的不好。
#include<cstdio>
#include<algorithm>
#define lrrt int L,int R,int rt
#define iall 1,n,1
#define imid int mid=(L+R)>>1
#define lson L,mid,rt<<1
#define rson mid+1,R,rt<<1|1
using namespace std;
typedef __int64 LL;
const int M=;
struct T{
LL sum;
bool cover;
}tree[M<<];
LL F[M];
int Flen=;
void initF(){
F[]=F[]=;
for(int i=;i<Flen;i++){
F[i]=F[i-]+F[i-];
}
}
int Findcloseid(LL val){
if(val<=) return ;
int id=lower_bound(F,F+Flen,val)-F;
if(abs(F[id-]-val)<=abs(F[id]-val)) id--;
return id;
}
void pushup(int rt){
tree[rt].sum=tree[rt<<].sum+tree[rt<<|].sum;
tree[rt].cover=tree[rt<<].cover&tree[rt<<|].cover;
}
void build(lrrt){
tree[rt].cover=;
tree[rt].sum=;
if(L==R) return ;
imid;
build(lson);
build(rson);
}
void add(int x,int val,lrrt){
if(L==R){
tree[rt].sum+=val;
int id=Findcloseid(tree[rt].sum);
tree[rt].cover=(F[id]==tree[rt].sum);
return ;
}
imid;
if(mid>=x) add(x,val,lson);
else add(x,val,rson);
pushup(rt);
}
void update(int x,int y,lrrt){
if(L==R){
tree[rt].cover=true;
tree[rt].sum=F[Findcloseid(tree[rt].sum)];
return ;
}
imid;
if(x<=L&&R<=y){
if(tree[rt].cover) return ;
update(x,y,lson);
update(x,y,rson);
pushup(rt);
return ;
}
if(mid>=x) update(x,y,lson);
if(mid<y) update(x,y,rson);
pushup(rt);
}
LL query(int x,int y,lrrt){
if(x<=L&&R<=y) return tree[rt].sum;
imid;
LL ans=;
if(mid>=x) ans+=query(x,y,lson);
if(mid<y) ans+=query(x,y,rson);
return ans;
}
int main(){
initF();
int n,m;
while(~scanf("%d%d",&n,&m)){
build(iall);
while(m--){
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(op==){
add(x,y,iall);
}
else if(op==){
printf("%I64d\n",query(x,y,iall));
}
else{
update(x,y,iall);
}
}
}
return ;
}
Scary Path Finding Algorithm http://acm.hdu.edu.cn/showproblem.php?pid=4889
#include<cstdio>
using namespace std;
int exp2[],c;
int main() {
exp2[] = ;
for(int i = ; i < ; i++) {
exp2[i] = exp2[i-] <<;
}
while(~scanf("%d",&c)) {
puts("61 90");
for(int i = ,j; i < ; i++) {
j=i<<;
printf("%d %d %d\n",+j,+j+,);
printf("%d %d %d\n",+j+,+j+, -exp2[-i]);
printf("%d %d %d\n",+j,+j+, -exp2[-i]);
}
}
return ;
}
The Great Pan http://acm.hdu.edu.cn/showproblem.php?pid=4891
模拟题。
#include<cstdio>
#include<cstring>
typedef __int64 LL;
const int M=;
char a[M][M];
int main(){
int n;
while(~scanf("%d",&n)){
getchar();
for(int i=;i<n;i++){
gets(a[i]);
}
LL ans=;
LL sa=,sb=;// ||| ' '
bool fa=,fb=;
bool big=false;
for(int i=;i<n;i++){
if(big) break;
int len=strlen(a[i]);
for(int j=;j<len;j++){
if(big) break;
if(a[i][j]=='{'){
fa=true;
sa=;
}
else if(a[i][j]=='}'){
fa=false;
ans*=(sa+);
if(ans>) big=true;
sa=;
}
else if(a[i][j]=='$'){
if(fb){
fb=false;
ans*=(sb+);
sb=;
}
else{
fb=true;
sb=;
}
}
else{
if(fa){
if(a[i][j]=='|'){
sa++;
}
}
else if(fb){
if(a[i][j]==' '){
int k;
for(k=j;k<len;k++){
if(a[i][k]==' ') sb++;
else break;
}
j=k-;
if(k==len){
if(i+<n&&a[i+][]==' ')
continue;
}
ans*=(sb+);
if(ans>) big=true;
sb=;
}
}
}
}
}
if(big){
puts("doge");
continue;
}
printf("%I64d\n",ans);
}
return ;
}
Redraw Beautiful Drawings http://acm.hdu.edu.cn/showproblem.php?pid=4888
最大流建图和判断多解有待研究。
我们建一个二部图,左边是行,右边是列,建个源点与行建边,容量是该行的和,列与新建的汇点建边,容量是该列的和,最后每行与每列建边,容量为题意中的k。建边如图:
跑一遍最大流,如果最大流等于行的和且等于列的和,那么就是有解的,否则无解。这样我们得到了一组解,行i到列j的流量即为i行j列的大小。之后便是判断是否有多种情况了。基本思路是这样的,我们看下图:
有多解的情况一定可以找到这样的4个位置:AB同行,CD同行,AC同列,BD同列,并且他们符合一下两种情况的其中一种:
1、AD未达到k(可变大),BC不是0(可减小)
2、AD不是0(可减小),BC未达到k(可变大)
不过枚举的话复杂度太高了,这里需要优化下。我建了一个二维数组cc[i][j],代表之前行是否有第i个可变大,第j个可减小的情况。这里枚举每一行,每一行再枚举两个位置i和j,如果当前行有i和j使得第i可以减小、第j个可以变大并且cc[i][j]为1,那么一定有多解。这里如果cc[i][j]为0,那么继续,同时cc[j][i]赋为1。这样的话就避免了最坏O(400^4)的复杂度,而变成了最多O(400^3)。
#include<cstdio>
#include<cstring>
#include<queue>
#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;
const int inf=0x7fffffff;
const int M=;
class Sap { //最大流sap算法O(V*E^2)
int n,head[M],dep[M],gap[M],cur[M],S[M],res,top,i,inser;
queue<int> q;
void bfs(int s,int t) {
mt(dep,-);
mt(gap,);
while(!q.empty()) q.pop();
gap[]=;
dep[t]=;
q.push(t);
while(!q.empty()) {
int u=q.front();
q.pop();
for(int i=head[u]; ~i; i=e[i].next) {
int v=e[i].v;
if(dep[v]!=-) continue;
q.push(v);
dep[v]=dep[u]+;
++gap[dep[v]];
}
}
}
public:
struct E {
int u,v,next,flow;
} e[M*M];
int le;
void init(int tn) {
n=tn;
le=;
mt(head,-);
}
void add(int u,int v,int flow) {
e[le].u=u;
e[le].v=v;
e[le].flow=flow;
e[le].next=head[u];
head[u]=le++;
e[le].u=v;
e[le].v=u;
e[le].flow=;
e[le].next=head[v];
head[v]=le++;
}
int solve(int s,int t) {
bfs(s,t);
res=top=;
for(i=;i<=n;i++) cur[i]=head[i];
int u=s;
while(dep[s]<n) {
if(u==t) {
int temp=inf;
for(i=; i<top; i++)
if(temp>e[S[i]].flow) {
temp=e[S[i]].flow;
inser=i;
}
for(i=; i<top; i++) {
e[S[i]].flow-=temp;
e[S[i]^].flow+=temp;
}
res+=temp;
top=inser;
u=e[S[top]].u;
}
if(u!=t&&!gap[dep[u]-]) break;
for(i=cur[u]; ~i; i=e[i].next)
if(e[i].flow&&dep[u]==dep[e[i].v]+)
break;
if(~i) {
cur[u]=i;
S[top++]=i;
u=e[i].v;
} else {
int sma=n;
for(i=head[u]; ~i; i=e[i].next) {
if(!e[i].flow) continue;
if(sma>dep[e[i].v]) {
sma=dep[e[i].v];
cur[u]=i;
}
}
--gap[dep[u]];
dep[u]=sma+;
++gap[dep[u]];
if(u!=s) u=e[S[--top]].u;
}
}
return res;
}
} gx;
int n,m,k,suma,sumb,a[M>>],b[M>>],mp[M>>][M>>];
bool dou[M>>][M>>];//dou[0][i] i这列存在一个可增的点
int solve(){
if(suma!=sumb) return -;
int s=,t=n+m+;
gx.init(t+);
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
gx.add(i,j+n,k);
}
}
for(int i=;i<=n;i++){
gx.add(s,i,a[i]);
}
for(int i=;i<=m;i++){
gx.add(i+n,t,b[i]);
}
if(gx.solve(s,t)!=suma) return -;
int eid=;
for(int i=;i<=n;i++){
for(int j=;j<=m;j++,eid+=){
mp[i][j]=gx.e[eid].flow;
}
}
mt(dou,);
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
for(int z=j+;z<=m;z++){
bool v1=false,v2=false;
if(mp[i][j]!=k&&mp[i][z]!=){
if(dou[z][j]) return ;
v1=;
}
if(mp[i][j]!=&&mp[i][z]!=k){
if(dou[j][z]) return ;
v2=;
}
if(v1) dou[j][z]=true;
if(v2) dou[z][j]=true;
}
}
}
return ;
}
int main(){
while(~scanf("%d%d%d",&n,&m,&k)){
suma=sumb=;
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
suma+=a[i];
}
for(int i=;i<=m;i++){
scanf("%d",&b[i]);
sumb+=b[i];
}
int ans=solve();
if(ans==-){
puts("Impossible");
}
else if(!ans){
puts("Not Unique");
}
else{
puts("Unique");
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
if(j>) printf(" ");
printf("%d",mp[i][j]);
}
puts("");
}
}
}
}
李队随机法选点测试,随机100次能ac。佩服。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;
const int inf=0x7fffffff;
const int M=;
class Sap { //最大流sap算法O(V*E^2)
int n,head[M],dep[M],gap[M],cur[M],S[M],res,top,i,inser;
queue<int> q;
void bfs(int s,int t) {
mt(dep,-);
mt(gap,);
while(!q.empty()) q.pop();
gap[]=;
dep[t]=;
q.push(t);
while(!q.empty()) {
int u=q.front();
q.pop();
for(int i=head[u]; ~i; i=e[i].next) {
int v=e[i].v;
if(dep[v]!=-) continue;
q.push(v);
dep[v]=dep[u]+;
++gap[dep[v]];
}
}
}
public:
struct E {
int u,v,next,flow;
} e[M*M];
int le;
void init(int tn) {
n=tn;
le=;
mt(head,-);
}
void add(int u,int v,int flow) {
e[le].u=u;
e[le].v=v;
e[le].flow=flow;
e[le].next=head[u];
head[u]=le++;
e[le].u=v;
e[le].v=u;
e[le].flow=;
e[le].next=head[v];
head[v]=le++;
}
int solve(int s,int t) {
bfs(s,t);
res=top=;
for(i=;i<=n;i++) cur[i]=head[i];
int u=s;
while(dep[s]<n) {
if(u==t) {
int temp=inf;
for(i=; i<top; i++)
if(temp>e[S[i]].flow) {
temp=e[S[i]].flow;
inser=i;
}
for(i=; i<top; i++) {
e[S[i]].flow-=temp;
e[S[i]^].flow+=temp;
}
res+=temp;
top=inser;
u=e[S[top]].u;
}
if(u!=t&&!gap[dep[u]-]) break;
for(i=cur[u]; ~i; i=e[i].next)
if(e[i].flow&&dep[u]==dep[e[i].v]+)
break;
if(~i) {
cur[u]=i;
S[top++]=i;
u=e[i].v;
} else {
int sma=n;
for(i=head[u]; ~i; i=e[i].next) {
if(!e[i].flow) continue;
if(sma>dep[e[i].v]) {
sma=dep[e[i].v];
cur[u]=i;
}
}
--gap[dep[u]];
dep[u]=sma+;
++gap[dep[u]];
if(u!=s) u=e[S[--top]].u;
}
}
return res;
}
} gx;
int n,m,k,suma,sumb,a[M>>],b[M>>],mp[M>>][M>>];
int solve(){
if(suma!=sumb) return -;
int s=,t=n+m+;
gx.init(t+);
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
gx.add(i,j+n,k);
}
}
for(int i=;i<=n;i++){
gx.add(s,i,a[i]);
}
for(int i=;i<=m;i++){
gx.add(i+n,t,b[i]);
}
if(gx.solve(s,t)!=suma) return -;
int eid=;
for(int i=;i<=n;i++){
for(int j=;j<=m;j++,eid+=){
mp[i][j]=gx.e[eid].flow;
}
}
bool ok=false; //李队随机法过
if(n!=&&m!=){
for(int t=; t<=; t++) { //随机100次就能找到 数据不强?
int i=rand()%(n-)+;
int j=rand()%(m-)+;
int ii=rand()%(n-i)++i;
int jj=rand()%(m-j)++j;
int lu=mp[i][j];
int ld=mp[ii][j];
int ru=mp[i][jj];
int rd=mp[ii][jj];
if(lu>&&rd>&&ld<k&&ru<k)ok=true;
if(lu<k&&rd<k&&ld>&&ru>)ok=true;
if(ok)break;
}
}
if(ok) return ;
return ;
}
int main(){
while(~scanf("%d%d%d",&n,&m,&k)){
suma=sumb=;
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
suma+=a[i];
}
for(int i=;i<=m;i++){
scanf("%d",&b[i]);
sumb+=b[i];
}
int ans=solve();
if(ans==-){
puts("Impossible");
}
else if(!ans){
puts("Not Unique");
}
else{
puts("Unique");
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
if(j>) printf(" ");
printf("%d",mp[i][j]);
}
puts("");
}
}
}
}
从源点向行连容量为行总和的边,从列向汇点连容量为列总和的边,从行->列连容量为K的边。这样跑出最大流,如果是满流就有解。判断多解就是判断最大流是否有多解。在残留网络中,如果能找到一个环,那么流量就可以从这个环绕一圈,而不改变最大流。这个dfs一下就好了。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;
const int inf=0x7fffffff;
const int M=;
class Sap { //最大流sap算法O(V*E^2)
int n,dep[M],gap[M],cur[M],S[M],res,top,i,inser;
queue<int> q;
void bfs(int s,int t) {
mt(dep,-);
mt(gap,);
while(!q.empty()) q.pop();
gap[]=;
dep[t]=;
q.push(t);
while(!q.empty()) {
int u=q.front();
q.pop();
for(int i=head[u]; ~i; i=e[i].next) {
int v=e[i].v;
if(dep[v]!=-) continue;
q.push(v);
dep[v]=dep[u]+;
++gap[dep[v]];
}
}
}
public:
struct E {
int u,v,next,flow;
} e[M*M];
int le,head[M];
void init(int tn) {
n=tn;
le=;
mt(head,-);
}
void add(int u,int v,int flow) {
e[le].u=u;
e[le].v=v;
e[le].flow=flow;
e[le].next=head[u];
head[u]=le++;
e[le].u=v;
e[le].v=u;
e[le].flow=;
e[le].next=head[v];
head[v]=le++;
}
int solve(int s,int t) {
bfs(s,t);
res=top=;
for(i=;i<=n;i++) cur[i]=head[i];
int u=s;
while(dep[s]<n) {
if(u==t) {
int temp=inf;
for(i=; i<top; i++)
if(temp>e[S[i]].flow) {
temp=e[S[i]].flow;
inser=i;
}
for(i=; i<top; i++) {
e[S[i]].flow-=temp;
e[S[i]^].flow+=temp;
}
res+=temp;
top=inser;
u=e[S[top]].u;
}
if(u!=t&&!gap[dep[u]-]) break;
for(i=cur[u]; ~i; i=e[i].next)
if(e[i].flow&&dep[u]==dep[e[i].v]+)
break;
if(~i) {
cur[u]=i;
S[top++]=i;
u=e[i].v;
} else {
int sma=n;
for(i=head[u]; ~i; i=e[i].next) {
if(!e[i].flow) continue;
if(sma>dep[e[i].v]) {
sma=dep[e[i].v];
cur[u]=i;
}
}
--gap[dep[u]];
dep[u]=sma+;
++gap[dep[u]];
if(u!=s) u=e[S[--top]].u;
}
}
return res;
}
} gx;
int n,m,k,suma,sumb,a[M>>],b[M>>],mp[M>>][M>>];
bool vis[M];
bool dfs(int u,int fa){
for(int i=gx.head[u];~i;i=gx.e[i].next){
int w=gx.e[i].flow;
if(w==) continue;
int v=gx.e[i].v;
if(v!=fa){
if(vis[v]) return true;
vis[v]=true;
if(dfs(v,u)) return true;
vis[v]=false;
}
}
return false;
}
int solve(){
if(suma!=sumb) return -;
int s=,t=n+m+;
gx.init(t+);
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
gx.add(i,j+n,k);
}
}
for(int i=;i<=n;i++){
gx.add(s,i,a[i]);
}
for(int i=;i<=m;i++){
gx.add(i+n,t,b[i]);
}
if(gx.solve(s,t)!=suma) return -;
int eid=;
for(int i=;i<=n;i++){
for(int j=;j<=m;j++,eid+=){
mp[i][j]=gx.e[eid].flow;
}
}
mt(vis,);
for(int i=;i<=n;i++){
if(dfs(i,-)){
return ;
}
}
return ;
}
int main(){
while(~scanf("%d%d%d",&n,&m,&k)){
suma=sumb=;
for(int i=;i<=n;i++){
scanf("%d",&a[i]);
suma+=a[i];
}
for(int i=;i<=m;i++){
scanf("%d",&b[i]);
sumb+=b[i];
}
int ans=solve();
if(ans==-){
puts("Impossible");
}
else if(!ans){
puts("Not Unique");
}
else{
puts("Unique");
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
if(j>) printf(" ");
printf("%d",mp[i][j]);
}
puts("");
}
}
}
}
end
2014 Multi-University Training Contest 3的更多相关文章
- HDU4888 Redraw Beautiful Drawings(2014 Multi-University Training Contest 3)
Redraw Beautiful Drawings Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- hdu 4946 2014 Multi-University Training Contest 8
Area of Mushroom Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) ...
- 2014 Multi-University Training Contest 9#11
2014 Multi-University Training Contest 9#11 Killing MonstersTime Limit: 2000/1000 MS (Java/Others) ...
- 2014 Multi-University Training Contest 9#6
2014 Multi-University Training Contest 9#6 Fast Matrix CalculationTime Limit: 2000/1000 MS (Java/Oth ...
- 2014 Multi-University Training Contest 1/HDU4861_Couple doubi(数论/法)
解题报告 两人轮流取球,大的人赢,,, 贴官方题解,,,反正我看不懂.,,先留着理解 关于费马小定理 关于原根 找规律找到的,,,sad,,, 非常easy找到循环节为p-1,每个循环节中有一个非零的 ...
- 2014 Multi-University Training Contest 1/HDU4864_Task(贪心)
解题报告 题意,有n个机器.m个任务. 每一个机器至多能完毕一个任务.对于每一个机器,有一个最大执行时间Ti和等级Li,对于每一个任务,也有一个执行时间Tj和等级Lj.仅仅有当Ti>=Tj且Li ...
- hdu 4937 2014 Multi-University Training Contest 7 1003
Lucky Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) T ...
- hdu 4941 2014 Multi-University Training Contest 7 1007
Magical Forest Time Limit: 24000/12000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Other ...
- hdu 4939 2014 Multi-University Training Contest 7 1005
Stupid Tower Defense Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/ ...
- hdu 4930 Fighting the Landlords--2014 Multi-University Training Contest 6
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4930 Fighting the Landlords Time Limit: 2000/1000 MS ...
随机推荐
- java web服务器文件的下载(有下载弹出匡)
昨天做了一个文件从服务下载的功能,怎么都不弹出页面,下载框.后查询得知.目前两种方法 1.<a href='下载路径' /> 2.window.location.href = basePa ...
- JQuery的复选框选中、取消、全选,全不选问题
一.必须引入JQuery库: 下面是js代码: /*** * 服务管理块>>>复选框事件处理 */ //服务管理复选框被选中.取消$(function(){ $("#Ser ...
- (转)Centos5.5安装MONO2.10.8和Jexus 5.0开启Linux平台.net应用新篇章
注:本文只做本人记录使用,也可供大家参考,有兴趣的可以一起讨论. 安装步骤 1.yum –y update 2.安装Mono源码安装需要的库 yum -y install gcc gcc-c++ bi ...
- CSS伪对象选择符整理
1.E::selection 2.E::placeholder 1. E::selection 设置对象被选择时的样式. 需要注意的是,::selection只能定义被选择时的background-c ...
- hdu 2955 Robberies 0-1背包/概率初始化
/*Robberies Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total S ...
- (转载)浅谈我对DDD领域驱动设计的理解
原文地址:http://www.cnblogs.com/netfocus/p/5548025.html 从遇到问题开始 当人们要做一个软件系统时,一般总是因为遇到了什么问题,然后希望通过一个软件系统来 ...
- centos6.5下的mysql5.6.30安装
1.解压mysql tar -xf mysql-5.6.30-linux-glibc2.5-x86_64.tar.gz -C /usr/local mv mysql-5.6.30-linux-gli ...
- Linux常用命令操作说明(链接)
1. Busybox下tftp命令使用详解 2. Linux中rc的含义 3. <Unix文件系统结构标准>(Filesystem Hierarchy Standard) 4. 用size ...
- php基础小知识
1.php中的双引号可以正确的解析变量与转义序列,而单引号只会按照声明原样显示:双里面的字段会经过编译器解释,然后再当作HTML代码输出:单引号里面的不进行解释,直接输出. 2.转义序列是针对源代码的 ...
- (IIS8/8.5/Apache)301域名重定向
用Apache的.htaccess来做301域名转向1.开启apache支持.htaccess,方法:在Apache的配置文件httpd.conf中,找到<Directory /> ...