bzoj

Posted on 2017-08-21 15:54  Amphetamine  阅读(198)  评论(0编辑  收藏  举报

1001: [BeiJing2006]狼抓兔子

Time Limit: 15 Sec  Memory Limit: 162 MB

Description

现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,
而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:

 

左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 
1:(x,y)<==>(x+1,y) 
2:(x,y)<==>(x,y+1) 
3:(x,y)<==>(x+1,y+1) 
道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上角和右下角为兔子的两个窝,
开始时所有的兔子都聚集在左上角(1,1)的窝里,现在它们要跑到右下解(N,M)的窝中去,狼王开始伏击
这些兔子.当然为了保险起见,如果一条道路上最多通过的兔子数为K,狼王需要安排同样数量的K只狼,
才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的
狼的数量要最小。因为狼还要去找喜羊羊麻烦.

Input

第一行为N,M.表示网格的大小,N,M均小于等于1000.
接下来分三部分
第一部分共N行,每行M-1个数,表示横向道路的权值. 
第二部分共N-1行,每行M个数,表示纵向道路的权值. 
第三部分共N-1行,每行M-1个数,表示斜向道路的权值. 
输入文件保证不超过10M

Output

输出一个整数,表示参与伏击的狼的最小数量.

Sample Input

3 4
5 6 4
4 3 1
7 5 3
5 6 7 8
8 7 6 5
5 5 5
6 6 6

Sample Output

14

HINT

 

 

都说是什么平面图转对偶图,但是,这难道不是赤裸裸的最小割嘛?

别忘了建边的时候,正反都要有流量,因为都需要。

 

#include<bits/stdc++.h>
using namespace std; 
#define inf 2147483647
#define ll long long
inline int read(){
    int x=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();
    }
    return x;
} 
int n,m,s,t;
int ip;
struct E{
    int to;ll cap;
}e[8000100];
vector<int> l[1000100];
int lv[1000100];
int b[1000100];
bool bfs(){
    memset(lv,-1,sizeof(lv));
    lv[s]=0;
    queue<int>q;
    q.push(s);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=0;i<l[u].size();i++){
            int t=l[u][i];
            int v=e[t].to;
            if(lv[v]==-1&&e[t].cap>0){
                lv[v]=lv[u]+1;
                q.push(v);
            }
        }
    }
    return lv[t]!=-1;
}
int dfs(int now,int mf){
    if(now==t||mf==0)return mf;
    ll tf=mf;
    for(;b[now]<l[now].size();b[now]++){
            int t=l[now][b[now]];
            int v=e[t].to;
            if(lv[v]==lv[now]+1&&e[t].cap!=0){
                ll f=dfs(v,min(tf,e[t].cap));
                tf-=f;
                e[t].cap-=f;
                e[t^1].cap+=f;
                if(tf==0)return mf;
            }
        }
    lv[now]=-1;
    return mf-tf;
}
int dinic(){
    ll ret=0;
    while(bfs()){
    memset(b,0,sizeof(b));
        ret+=dfs(s,inf);
    }
    return ret;
}
void insert(int u,int v,int c){
    e[ip].to=v;
    e[ip].cap=c;
    l[u].push_back(ip++);
}
int main(){
    n=read(),m=read();
    s=1;t=n*m;
    int x;
    for(int i=1;i<=n;i++)
        for(int j=1;j<m;j++)
        {
            scanf("%d",&x);
            insert(m*(i-1)+j,m*(i-1)+j+1,x);
            insert(m*(i-1)+j+1,m*(i-1)+j,x);
        }
    for(int i=1;i<n;i++)
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&x);
            insert(m*(i-1)+j,m*(i)+j,x);
            insert(m*(i)+j,m*(i-1)+j,x);
        }
    for(int i=1;i<n;i++)
        for(int j=1;j<m;j++)
        {
            scanf("%d",&x);
            insert(m*(i-1)+j,m*(i)+j+1,x);
            insert(m*(i)+j+1,m*(i-1)+j,x);
        }
    cout<<dinic();
    return 0;
}
View Code

 

1002: [FJOI2007]轮状病毒

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 5577  Solved: 3031
[Submit][Status][Discuss]

Description

  轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的。一个N轮状基由圆环上N个不同的基原子
和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道。如下图所示

  N轮状病毒的产生规律是在一个N轮状基中删去若干条边,使得各原子之间有唯一的信息通道,例如共有16个不
同的3轮状病毒,如下图所示

  现给定n(N<=100),编程计算有多少个不同的n轮状病毒

 

Input

  第一行有1个正整数n

Output

  计算出的不同的n轮状病毒数输出

 
找规律啊
基尔霍夫矩阵???
高精度!
代码就不贴了

1007: [HNOI2008]水平可见直线

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 7590  Solved: 2902
[Submit][Status][Discuss]

Description

  在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为
可见的,否则Li为被覆盖的.
例如,对于直线:
L1:y=x; L2:y=-x; L3:y=0
则L1和L2是可见的,L3是被覆盖的.
给出n条直线,表示成y=Ax+B的形式(|A|,|B|<=500000),且n条直线两两不重合.求出所有可见的直线.

Input

  第一行为N(0 < N < 50000),接下来的N行输入Ai,Bi

Output

  从小到大输出可见直线的编号,两两中间用空格隔开,最后一个数字后面也必须有个空格

Sample Input

3
-1 0
1 0
0 0

Sample Output

1 2
 
这是啥啊,计算几何。
按照斜率排序,因为斜率大的永远不可能被斜率小的盖住。
将直线推入栈里。计算直线的交点,如果交点在上一个交点在右边则继续,在左边则弹栈。
#include<bits/stdc++.h>
using namespace std;
#define eps 1e-8
int n;
struct T{
    double a,b;
    int num;
}l[50001],st[50001];
bool ans[50001];int top;
double crossx(T x1,T x2)
{return (x2.b-x1.b)/(x1.a-x2.a);}
void insert(T a)
{
    while(top)
    {
        if(fabs(st[top].a-a.a)<eps)top--;
        else if(top>1&&crossx(a,st[top-1])<=crossx(st[top],st[top-1]))
            top--;
        else break;
    }
    st[++top]=a;
}
void work()
{
    for(int i=1;i<=n;i++)insert(l[i]);
    for(int i=1;i<=top;i++)ans[st[i].num]=1;
    for(int i=1;i<=n;i++)
       if(ans[i])printf("%d ",i);
}
bool cmp(T w,T e){
    if(fabs(w.a-e.a)<eps)return  w.b<e.b;
    else return w.a<e.a;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lf%lf",&l[i].a,&l[i].b);
        l[i].num=i;
    }
    sort(l+1,l+n+1,cmp);
    work();
    return 0;
}
View Code

 

 小插曲  刚才Never Penta kill 问我一道题

1658: [Usaco2006 Mar]Water Slides 滑水

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 231  Solved: 152
[Submit][Status][Discuss]

Description

It's a hot summer day, and Farmer John is letting Betsy go to the water park where she intends to ride every single slide. The water park has N (1 <= N <= 10,000) platforms (numbered 1..N) from which to enter the M (1 <= M <= 10,000) water slides. Each water slide starts at the top of some platform and ends at the bottom of some platform (possibly the same one). Some platforms might have more than one slide; some might not have any. The park is very thin, so the platforms lie along a straight line, each platform at a position Xi (0 <= Xi <= 100,000) meters from one end of the park. One walks from one platform to the next via a sidewalk parallel to the line of platforms.The platforms of the water park are weakly connected; that is, the park cannot be divided into two sets of platforms with no slides running between the two sets. Both the entrance and exit to the park are at platform 1, so Betsy will start and end there. In order to spend more time on the slides, Betsy wants to walk as little as possible. Find the minimum distance Betsy must travel along the ground in order to try every slide in the park exactly once without repeating.

 

    炎热的夏日里,约翰带贝茜去水上乐园滑水.滑水是在一条笔直的人工河里进行的,沿河设有N(1≤N≤10000)个中转站,并开通了M(1≤M≤10000)条滑水路线.路线的起点和终点总在某个中转站上,起点和终点可能相同.有些中转站可能是许多条路线的起点或终点,而有些站则可能没有在任何路线里被用上.贝茜希望能把所有的路线都滑一遍.    所有中转站排成一条直线,每个中转站位于离河的源头Xi(0≤Xi≤100000)米处.沿着河边的人行道,贝茜可以从任意位置走到任意一个中转站.    中转站与滑水路线的布局满足下述的性质:任意两个中转站之间都有滑水路线直接成间接相连.水上乐园的入口与出口都在1号中转站旁,也就是说,贝茜的滑水路线的起点和终点都是1号中转站.

    为了更好地享受滑水的快乐,贝茜希望自己花在走路上的时间越少越好.请你帮她计算一下,如果按她的计划,把所有的路线都不重复地滑一遍,那她至少要走多少路.

 

Input

* Line 1: Two integers, N and M.

* Lines 2..N+1: Line i+1 contains one integer, Xi, the position of platform i. * Lines N+2..M+N+1: Line i+N+1 contains two integers, Si and Di, respectively the start and end platforms of a slide.

    第1行:两个整数N和M,用空格隔开.

    第2到N+1行:第i+l行包括一个整数Xi,表示i号中转站距河源头的距离.

    第N+2到M+N+1行:第i+N+1行包括两个整数Si和Di,分别表示了一条滑水路线的起点和终点.

 

Output

* Line 1: One integer, the minimum number of meters Betsy must walk.

    输出一个整数,即贝茜要走的路程长度至少为多少米

Sample Input

5 7
5
3
1
7
10
1 2
1 2
2 3
3 1
4 5
1 5
4 1

Sample Output

8

HINT

 

   贝茜先按1~2~3~1~2路径滑水.然后走2米,回到1.她再滑行到5,走到4,滑行


到5,走到4,最后滑回1(数字代表中转站号).


    这样,她所走的总路程为8米.

 
题意不好懂。。。
读懂题意也不好做。这是一道贪心题,但是很不好想。
首先,记每个点的出度入度,然后出度入度相减。
为什么这么做呢???
因为这样可以直接消去所有的环,剩下的就是必须要走的路了。
然后,剩下的就是一堆起点和终点。然后按照位置排序起点终点。然后对应的起点终点相减就是最小的了。
#include <bits/stdc++.h>
using namespace std;
int n,m;
int pos[10010],s[10010],d[10010],du[10010];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",pos+i);
    int x,y;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        du[x]++;du[y]--;
    }
    int a=0,b=0;
    for(int i=1;i<=n;i++){
        for(;du[i]>0;du[i]--)s[++a]=pos[i];
        for(;du[i]<0;du[i]++)d[++b]=pos[i];
    }
    sort(s+1,s+a+1);
    sort(d+1,d+b+1);
    int ans=0;
    for(int i=1;i<=a;i++){
        ans+=abs(s[i]-d[i]);
    }
    cout<<ans;
    return 0;
}
View Code

 

1008: [HNOI2008]越狱

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 9933  Solved: 4278
[Submit][Status][Discuss]

Description

  监狱有连续编号为1...N的N个房间,每个房间关押一个犯人,有M种宗教,每个犯人可能信仰其中一种。如果
相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱

Input

  输入两个整数M,N.1<=M<=10^8,1<=N<=10^12

Output

  可能越狱的状态数,模100003取余

Sample Input

2 3

Sample Output

6

HINT

 

  6种状态为(000)(001)(011)(100)(110)(111)

 
经典的计数问题。
第一个点有m种选择,后面的点都有m-1种选择
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 100003
ll power(ll a,ll b){
    if(b==0)return 1;
    else if(b&1)return power(a*a%mod,b>>1)*a%mod;
    else return power(a*a%mod,b>>1);
} 

int main() {
    ll n,m;
    cin>>m>>n;
    printf("%d",(power(m,n)-(m*power(m-1,n-1))%mod+mod)%mod);
}
View Code

 

1012: [JSOI2008]最大数maxnumber

Time Limit: 3 Sec  Memory Limit: 162 MB
Submit: 10829  Solved: 4739
[Submit][Status][Discuss]

Description

  现在请求你维护一个数列,要求提供以下两种操作:1、 查询操作。语法:Q L 功能:查询当前数列中末尾L
个数中的最大的数,并输出这个数的值。限制:L不超过当前数列的长度。2、 插入操作。语法:A n 功能:将n加
上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取
模,将所得答案插入到数列的末尾。限制:n是非负整数并且在长整范围内。注意:初始时数列是空的,没有一个
数。

Input

  第一行两个整数,M和D,其中M表示操作的个数(M <= 200,000),D如上文中所述,满足D在longint内。接下来
M行,查询操作或者插入操作。

Output

  对于每一个询问操作,输出一行。该行只有一个数,即序列中最后L个数的最大数。

Sample Input

5 100
A 96
Q 1
A 97
Q 1
Q 2

Sample Output

96
93
96

HINT

 

  数据如下http://pan.baidu.com/s/1i4JxCH3

 

啊啊啊啊啊,就这个破玩意,我当时写了一上午的线段树。。。

后来崩溃了,改成单调队列。1A。。。理论上单调队列可以卡成n方啊,,,为什么可以A啊

#include<bits/stdc++.h>
using namespace std;
int a[200001],m[2000001];
int main(){
    int n,d,l=0,x,ans=0;
    char f[4];
    scanf("%d%d",&n,&d);
    while(n--){
        scanf("%s%d",f,&x);
        if(f[0]=='A'){
            a[++l]=(x+ans)%d;
            for(int i=l;i>=1;i--){
                if(m[i]<a[l])m[i]=a[l];
                else break;
            }
        }
        else {
            ans=m[l-x+1];
            printf("%d\n",ans);
        }
    }
}
View Code

 

 

就这个效果。。。

 

1015: [JSOI2008]星球大战starwar

Time Limit: 3 Sec  Memory Limit: 162 MB
Submit: 6504  Solved: 3018
[Submit][Status][Discuss]

Description

  很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系。某一天,凭着一个偶然的
机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球。这些星球通过特殊的以太隧道互相直
接或间接地连接。 但好景不长,很快帝国又重新造出了他的超级武器。凭借这超级武器的力量,帝国开始有计划
地摧毁反抗军占领的星球。由于星球的不断被摧毁,两个星球之间的通讯通道也开始不可靠起来。现在,反抗军首
领交给你一个任务:给出原来两个星球之间的以太隧道连通情况以及帝国打击的星球顺序,以尽量快的速度求出每
一次打击之后反抗军占据的星球的连通快的个数。(如果两个星球可以通过现存的以太通道直接或间接地连通,则
这两个星球在同一个连通块中)。

Input

  输入文件第一行包含两个整数,N (1  < =  N  < =  2M) 和M (1  < =  M  < =  200,000),分别表示星球的
数目和以太隧道的数目。星球用 0 ~ N-1的整数编号。接下来的M行,每行包括两个整数X, Y,其中(0 < = X <> 
Y 表示星球x和星球y之间有“以太”隧道,可以直接通讯。接下来的一行为一个整数k,表示将遭受攻击的星球的
数目。接下来的k行,每行有一个整数,按照顺序列出了帝国军的攻击目标。这k个数互不相同,且都在0到n-1的范
围内。

Output

第一行是开始时星球的连通块个数。接下来的K行,每行一个整数,表示经过该次打击后现存星球
的连通块个数。

Sample Input

8 13
0 1
1 6
6 5
5 0
0 6
1 2
2 3
3 4
4 5
7 1
7 2
7 6
3 6
5
1
6
3
5
7

Sample Output

1
1
1
2
3
3
 
逆向并查集,先离线,然后反着做。
就相当于把删边操作转化成了加边操作,然后并查集即可。
 
 

1022: [SHOI2008]小约翰的游戏John

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 2820  Solved: 1794
[Submit][Status][Discuss]

Description

  小约翰经常和他的哥哥玩一个非常有趣的游戏:桌子上有n堆石子,小约翰和他的哥哥轮流取石子,每个人取
的时候,可以随意选择一堆石子,在这堆石子中取走任意多的石子,但不能一粒石子也不取,我们规定取到最后一
粒石子的人算输。小约翰相当固执,他坚持认为先取的人有很大的优势,所以他总是先取石子,而他的哥哥就聪明
多了,他从来没有在游戏中犯过错误。小约翰一怒之前请你来做他的参谋。自然,你应该先写一个程序,预测一下
谁将获得游戏的胜利。

Input

  本题的输入由多组数据组成第一行包括一个整数T,表示输入总共有T组数据(T≤500)。每组数据的第一行包
括一个整数N(N≤50),表示共有N堆石子,接下来有N个不超过5000的整数,分别表示每堆石子的数目。

Output

  每组数据的输出占一行,每行输出一个单词。如果约翰能赢得比赛,则输出“John”,否则输出“Brother”
,请注意单词的大小写。

Sample Input

2
3
3 5 1
1
1

Sample Output

John
Brother
 
博弈论反过来,注意特判
#include<bits/stdc++.h>
using namespace std; 
#define inf 2147483647
#define ll long long
inline int read(){
    int x=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();
    }
    return x;
} 
int main(){
    int t=read();
    while(t--){
        int n=read();
        int x=0;
        int p;
        int f=0;
        for(int i=1;i<=n;i++){
            p=read();
            x^=p;
            if(p!=1)f=1;
        }
        if((x!=0&&f==1)||(x==0&&f==0))printf("John\n");
        else printf("Brother\n");
    }
    return 0;
}
View Code

1024: [SCOI2009]生日快乐

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 2841  Solved: 2074
[Submit][Status][Discuss]

Description

  windy的生日到了,为了庆祝生日,他的朋友们帮他买了一个边长分别为 X 和 Y 的矩形蛋糕。现在包括windy
,一共有 N 个人来分这块大蛋糕,要求每个人必须获得相同面积的蛋糕。windy主刀,每一切只能平行于一块蛋糕
的一边(任意一边),并且必须把这块蛋糕切成两块。这样,要切成 N 块蛋糕,windy必须切 N-1 次。为了使得
每块蛋糕看起来漂亮,我们要求 N块蛋糕的长边与短边的比值的最大值最小。你能帮助windy求出这个比值么?

Input

  包含三个整数,X Y N。1 <= X,Y <= 10000 ; 1 <= N <= 10

Output

  包含一个浮点数,保留6位小数。

Sample Input

5 5 5

Sample Output

1.800000
 
dddddfs????
我刚看到这道题也是很懵逼的还以为有啥高级的算法呢,原来还真是dfs
 
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1e9
double dfs(double x,double y,int cnt){
    if(cnt==1)return max(x/y,y/x);
    double maxn=inf;
    for(int i=1;i<=cnt>>1;i++){
        maxn=min(maxn,max(dfs(x/cnt*i,y,i),dfs(x/cnt*(cnt-i),y,cnt-i)));
        maxn=min(maxn,max(dfs(x,y/cnt*i,i),dfs(x,y/cnt*(cnt-i),cnt-i)));
    }
    return maxn;
}
int main() {
    double x,y;int n;
    cin>>x>>y>>n;
    printf("%.6lf",dfs(x,y,n));
    return 0;
}
View Code