Problem A LZDFDSMLL吃批萨(easy)

http://murphyc.fun/contest/5/problem/A

Description

LZDFDSMLL最近收到了一个批萨,这个批萨可以表示成n行m列的矩形,已知这个批萨上有k块被吃掉了。

LZDFDSMLL一定要吃一块完整的正方形的批萨,请问他有多少种不同的批萨可以吃。

不同批萨的定义:

两个正方形批萨只要左上角的点不一样, 或者正方形批萨的边长不一样就算不同。

Input

第一行两个正数n,m, k, 分别表示矩阵的行数、矩阵的列数、被吃掉的块数。

接下来有k行,每行有两个数x, y, 表示在x行y列的那块批萨被吃掉了。

(1 <= n, m <= 500, k <= min(500, n*m))

Output

一个整数表示LZDFDSMLL有多少种不同的正方形批萨可以吃。

Sample Input 1 

3 3 0

Sample Output 1

14

Sample Input 2 

3 3 1
2 2

Sample Output 2

8

题意:

题解:

DP

动态规划,状转方程:

if (a[i][j]==1) f[i][j]=min(min(f[i][j-1],f[i-1][j]),f[i-1][j-1])+1;

说明:

f[i][j]表示以节点i,j为右下角,可构成的最大正方形的边长。

只有a[i][j]==1时,节点i,j才能作为正方形的右下角;

对于一个已经确定的f[i][j]=x,它表明包括节点i,j在内向上x个节点,向左x个节点扫过的正方形中所有a值都为1;

对于一个待确定的f[i][j],我们已知f[i-1][j],f[i][j-1],f[i-1][j-1]的值,如下:

f数组:

? ? ? ?

? ? 2 1

? ? 3 ?

? ? ? ?

则说明原a数组:

1 1 1 0

1 1 1 1

1 1 1 1

? ? ? ?

由此得出状态转移方程:

if (a[i][j]==1) f[i][j]=min(min(f[i][j-1],f[i-1][j]),f[i-1][j-1])+1;

for example:

a[i][j]:

0 0 0 1

1 1 1 1

0 1 1 1

1 1 1 1

f[i][j]:

0 0 0 1

1 1 1 1

0 1 2 2

1 1 2 3

/*
*@Author:   STZG
*@Language: C++
*/
#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
//#define DEBUG
#define RI register int
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=5000+10;
const int MOD=1e9+7;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
int t,n,m,k,q,x,y;
ll ans,cnt,flag,temp;
int a[N][N];
int l[N][N];
int c[N][N];
int dp[N][N];
char str;
int main()
{
#ifdef DEBUG
	freopen("input.in", "r", stdin);
	//freopen("output.out", "w", stdout);
#endif
    scanf("%d%d%d",&n,&m,&k);
    //scanf("%d",&t);
    //while(t--){}
    for(int i=1;i<=k;i++){
        scanf("%d%d",&x,&y);
        a[x][y]=1;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(!a[i][j])
            dp[i][j]=min(min(dp[i][j-1],dp[i-1][j]),dp[i-1][j-1])+1;
            //cout<<dp[i][j]<<endl;
            ans+=dp[i][j];
        }
    }
    cout<<ans<<endl;

    //cout << "Hello world!" << endl;
    return 0;
}

Problem B duxing201606的日期薄

http://murphyc.fun/contest/5/problem/B

Description

众所周知,duxing哥爱出去旅游。众所周知,duxing哥会各地脏话。

duxing哥有一个日期薄,上面有1,2,3...x代表了日期。每次duxing哥出去旅游或者回家的时候,都会在日期本上打一个标记,而且duxing哥有个习惯,就是不会在同一天出去和回来,这意味着一个日期上不会出现两个标记。duxing哥是这样计算日期的,假如在第a天有一个标记,在第b天有一个标记(b>a),那么a到b有b-a天。通过这样打标记,duxing哥很容易就能知道自己在这x天中有几天在外面玩耍,有几天在家学习。

例如duxing哥的日期薄可以是这个样子的:

其中第1,4,7,9,10,11打上了标记,那么第1天早上,duxing哥出去,第4天回家,那么这段时间内duxing哥都在玩耍,所以这段时间他玩了3天,同理之后的标记也可以这样理解,这样duxing哥一共玩了3+2+1=6天

可惜duxing哥有时会忘掉打标记。在第x天,duxing哥恰好旅游完回到了家,他打上了标记,在查看日期薄的时候,他看到在日期薄上有n个标记,可是duxing哥明明记得自己打了k+n个标记。duxing哥便打算把这k个标记补上,而duxing哥认为自己是一个非常贪玩的人,所以他希望在补上标记以后,自己玩耍的时间尽可能的多。

duxing哥很聪明,因为今天是第x天,所以他不可能把补上的标记打到x之后的日期,同时他也会遵循自己的习惯,不会在打过标记的日期位置再打一次。

但是duxing哥还有好多题目要验,所以他决定悬赏高达136948的v金来帮他解决这个问题。

Input

第一行输入两个数字,n,k,分别代表duxing哥已经有的标记数,duxing哥需要补的标记数,保证(n+k)%2=0 (1<=n<=1000,0<=k<=1000)

第二行输入n个数字,a1,a2,a3...an,其中a1<a2<a3...<an,并且a1=1,an=x,x为最后一天的标记,保证 n+k<=x (2<=x<=3000)

Output

输出一个数字,代表duxing哥在补上标记后玩了多少天

Sample Input 1 

6 0
1 4 7 9 10 11

Sample Output 1

6

Sample Input 2 

5 1
1 3 6 8 13

Sample Output 2

9

Sample Input 3 

5 3
1 3 6 8 13

Sample Output 3

9

Hint

样例1就是上面的图片样

例2中:标记在2或者4最优样

例3中:标记在2,7,9最优

题意:

题解:

C++版本一

 

Problem C duxing201606的原味鸡树

http://murphyc.fun/contest/5/problem/C

Description

众所周知,duxing哥非常喜欢原味鸡。众所周知,原味鸡是长在原味鸡树上的。

duxing哥因为是水产巨子,所以就购买了一棵原味鸡树。原味鸡树是一颗有n个节点的完全二叉树(节点编号从1开始),每个节点会长出一个原味鸡。每当duxing哥想吃原味鸡的时候,他就会在原味鸡树上挑选一个节点,然后将这个节点的子树上的原味鸡都吃掉(包括选中的那个节点)。

因为duxing哥害怕摘下的鸡不够他吃,所以现在duxing哥想知道当他选择某个节点的时候能吃到多少原味鸡。

Input

第一行n,m,其中n代表这颗树有多少个节点,m代表duxing哥的询问次数(1<=n<=1e9,1<=m<=100000)

接下来m行,每行一个数字x,代表duxing哥询问的节点编号

Output

对于duxing哥的每次询问,输出一个数字代表他能吃到多少原味鸡

Sample Input 1 

10 4
5
3
6
2

Sample Output 1

2
3
1
6

Hint

如图5号节点的子树包括5,6,所以答案为2

3号节点的子树包括3,6,7,所以答案为3

6号节点的子树包括6,所以答案为1

2号节点的子树包括2,4,5,8,9,10,所以答案为6

题意:

题解:

C++版本一

/*
*@Author:   STZG
*@Language: C++
*/
#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
//#define DEBUG
#define RI register int
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=100000000+10;
const int MOD=1e9+7;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
int t,n,m,k,q;
int ans,cnt,flag,temp;
int main()
{
#ifdef DEBUG
	freopen("input.in", "r", stdin);
	//freopen("output.out", "w", stdout);
#endif
    scanf("%d",&n);
    cnt=0;
    for(int i=1;i<=n;i*=2){
        cnt++;
    }
    //cout<<cnt;
    //build(1,pow(2,cnt-1),1);
    scanf("%d",&t);
    while(t--){
        scanf("%d",&k);
        int a=k;
        int b=k;
        q=1;
        while(a<pow(2,cnt-1))
            a*=2,q++;
        while(b<pow(2,cnt-1))
            b=2*b+1;
        if(n<a)
            ans=pow(2,q-1)-1;
        else if(b<n)
            ans=pow(2,q)-1;
        else
            ans=pow(2,q-1)+n-a;
        cout << ans << endl;
    }


    //cout << "Hello world!" << endl;
    return 0;
}

Problem D LZDFDSMLL吃批萨

http://murphyc.fun/contest/5/problem/D

Description

LZDFDSMLL最近收到了一个批萨,这个批萨可以表示成n行m列的矩形,已知这个批萨上有k块被吃掉了。

LZDFDSMLL一定要吃一块完整的正方形的批萨,请问他有多少种不同的批萨可以吃。

不同批萨的定义:

两个正方形批萨只要左上角的点不一样, 或者正方形批萨的边长不一样就算不同。

Input

第一行两个正数n,m, k, 分别表示矩阵的行数、矩阵的列数、被吃掉的块数。

接下来有k行,每行有两个数x, y, 表示在x行y列的那块批萨被吃掉了。

(1 <= n, m <= 5000, k <= min(5000, n*m))

Output

一个整数表示LZDFDSMLL有多少种不同的正方形批萨可以吃。

Sample Input 1 

3 3 0

Sample Output 1

14

Sample Input 2 

3 3 1
2 2

Sample Output 2

8

C++版本一

题解:DP

/*
*@Author:   STZG
*@Language: C++
*/
#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
//#define DEBUG
#define RI register int
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=5000+10;
const int MOD=1e9+7;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
int t,n,m,k,q,x,y;
ll ans,cnt,flag,temp;
int a[N][N];
int l[N][N];
int c[N][N];
int dp[N][N];
char str;
int main()
{
#ifdef DEBUG
	freopen("input.in", "r", stdin);
	//freopen("output.out", "w", stdout);
#endif
    scanf("%d%d%d",&n,&m,&k);
    //scanf("%d",&t);
    //while(t--){}
    for(int i=1;i<=k;i++){
        scanf("%d%d",&x,&y);
        a[x][y]=1;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(!a[i][j])
            dp[i][j]=min(min(dp[i][j-1],dp[i-1][j]),dp[i-1][j-1])+1;
            //cout<<dp[i][j]<<endl;
            ans+=dp[i][j];
        }
    }
    cout<<ans<<endl;

    //cout << "Hello world!" << endl;
    return 0;
}

 

Problem E 

 

题意:

题解:

C++版本一

 

Problem F 

 

题意:

题解:

C++版本一

 

Problem G plw的骰子

http://murphyc.fun/contest/5/problem/G 

Description

duxing2016有一个神奇的骰子,投出1-6的概率为(p1,p2...p6)

现在他投n次骰子,问投出点数和大于等于m的概率是多少

Input

第一行,两个正整数n,m

第二行,六个浮点数 p1,p2,p3,p4,p5,p6

n <= 1000, n <= m <= 6 * n

0<=pi<=1, (p1+p2+p3+p4+p5+p6) = 1

Output

投出点数和大于m的概率p,你的答案与std的误差要<=1e-5

Sample Input 1 

2 7
0 0 0.5 0 0 0.5

Sample Output 1

0.75 

题解:

设dp[i][j]为扔完i次骰子后得到的点数和为j的概率,那么很显然转移方程
 

dp[i + 1][j + k] = dp[i][j] * p[k], 1<=k<=6

初始条件也十分的显然,扔0次骰子得到点数和为0概率是1
第一维可以让k从大到小枚举而省去,因为每次肯定是从小的点数转移到大的点数

/*
*@Author:   STZG
*@Language: C++
*/
#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
//#define DEBUG
#define RI register int
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=1000+10;
const int MOD=1e9+7;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
int t,n,m,k,q;
double ans,cnt,flag,temp;
double a[N];
double dp[N][N*6];
char str;
int main()
{
#ifdef DEBUG
	freopen("input.in", "r", stdin);
	//freopen("output.out", "w", stdout);
#endif
    scanf("%d",&n);
    scanf("%d",&t);
    for(int i=1;i<=6;i++)
        scanf("%lf",&a[i]),dp[1][i]=a[i];
    dp[1][0]=1;
    for(int i=2;i<=n;i++){
        for(int j=1;j<=6;j++){
            for(int k=6*(i-1);k>=i-1;k--){
                    dp[i][k+j]=dp[i][k+j]+dp[i-1][k]*a[j];
            }
        }
    }
    ans=0;
    for(int j=6*n;j>=t;j--){
            ans+=dp[n][j];
           // cout<<dp[n][j]<<endl;
    }
    //while(t--){}
    printf("%.6f\n",ans);

    //cout << "Hello world!" << endl;
    return 0;
}

 

Problem H duxing201606的图灵奖

 

题意:

题解:

C++版本一

 

Problem I duxing201606玩游戏

http://murphyc.fun/contest/5/problem/I

Description

duxing201606喜欢看一款叫sc2的游戏,他发现在zvt时,经常会有拉狗引雷的操作,但是他自己操作不来,所有他想问问你:假设每颗雷的爆炸范围可能不一样,但是都是一个圆,只要狗走到圆内雷就会爆炸,最少需要拉几条狗引雷才能使雷全部爆炸?注意:因为两圆可能相交,所以有时候一条狗能引好几颗雷,雷和雷之间不会相互引爆.数据采用如下代码生成(rand()会产生一个0到2147483647的随机数):

2019-01-13 15-19-42屏幕截图.png

第i个雷坐标为(xi,yi),爆炸范围是ri,n为地雷数.

Input

多组测试,一个数n(n<=10).接下来n行,每行三个数x,y,z,表示坐标(x,y)和半径r

Output

最少的小狗数

Sample Input 1 

2
692314992 977213841 56
2140129659 884284570 108

Sample Output 1

2

题解:暴力解决一切问题

/*
*@Author:   STZG
*@Language: C++
*/
#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
//#define DEBUG
#define RI register int
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=100000+10;
const int MOD=1e9+7;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
int t,n,m,k,q;
int ans,cnt,flag,temp;
struct node{
    ll x,y,r;
}e[N];
char str;
double dist(ll x,ll y,ll x2,ll y2){
    return sqrt((x-x2)*(x-x2)+(y-y2)*(y-y2));
}
int main()
{
#ifdef DEBUG
	freopen("input.in", "r", stdin);
	//freopen("output.out", "w", stdout);
#endif
    while(~scanf("%d",&n)){
        ans=0;
        for(int i=1;i<=n;i++){
            scanf("%lld%lld%lld",&e[i].x,&e[i].y,&e[i].r);
            flag=1;
            for(int j=1;j<i;j++){
                if(dist(e[i].x,e[i].y,e[j].x,e[j].y)<=e[i].r+e[j].r){
                    flag=0;
                    break;
                }

            }
            ans+=flag;
        }
        cout<<ans<<endl;
    }
    //scanf("%d",&t);
    //while(t--){}


    //cout << "Hello world!" << endl;
    return 0;
}

 

Problem J 

 

题意:

题解:

C++版本一

 

Problem K 你真的会贪心吗?

 

题意:

题解:

C++版本一

 

Problem L plw的晚餐

http://murphyc.fun/contest/5/problem/L

Description

plw吃完午饭之后,马上又觉得肚子饿了。他决定马上从美食区离开,赶往下一个吃饭地点"香香鸡"。但是在plw离开离开美食区之前,需要按美食区的规矩画一个特殊符号,并且如果是这是第k次离开美食区,就需要画k倍大小的图形.

Input

多组测试

第一行输入T (T <= 10)

接下来T行,每一行输入一个k(k<=1000),代表这是第k次离开美食区。

Output

对于每次输入要求输出k倍大小的标准图形。

每2组测试数据之间输出一个空行。

注意不要输出多余的空行或者行末空格。

Sample Input 1 

2
1
2

Sample Output 1

 ___
/   \
\___/
_| |_
|___|

  ______
 /      \
/        \
\        /
 \______/
  |    |
__|    |__
|        |
|________|

C++版本一

/*
*@Author:   STZG
*@Language: C++
*/
#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
//#define DEBUG
#define RI register int
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=100000+10;
const int MOD=1e9+7;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
int t,n,m,k,q;
int ans,cnt,flag,temp;
int a[N];
char str;
int main()
{
#ifdef DEBUG
	freopen("input.in", "r", stdin);
	//freopen("output.out", "w", stdout);
#endif

    while(~scanf("%d",&t))
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            printf(" ");
        for(int i=1;i<=3*n;i++)
            printf("_");
            printf("\n");
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n-i;j++){
                printf(" ");
            }
            printf("/");
            for(int j=1;j<=2*(i-1)+3*n;j++){
                printf(" ");
            }
            printf("\\\n");
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<i;j++){
                printf(" ");
            }
            printf("\\");
            for(int j=1;j<=2*(n-i)+3*n;j++){
                if(i==n)
                printf("_");
                else
                printf(" ");
            }
            printf("/\n");
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(i==n)
                printf("_");
                else
                printf(" ");
            }
            printf("|");
            for(int j=1;j<=3*n-2;j++){
                printf(" ");
            }
            printf("|");
            for(int j=1;j<=n;j++){
                if(i==n)
                printf("_");
            }
            printf("\n");
        }
        for(int i=1;i<=n;i++){

            printf("|");

            for(int j=1;j<=5*n-2;j++){
                if(i==n)
                printf("_");
                else
                printf(" ");
            }
            printf("|");
            printf("\n");
        }

        if(t)
            printf("\n");
    }


    //cout << "Hello world!" << endl;
    return 0;
}

 

Problem M 

 

题意:

题解:

C++版本一

 

Problem N 

 

题意:

题解:

C++版本一