2019中山大学程序设计竞赛(HDU 6511-6521)

传送门:杭电6511-6521

目录

HDU6511 Min-Max

HDU6512 Triangle

HDU6513 Reverse it 

HDU6514 Monitor

HDU6515 Coding problem

HDU6516 Network

HDU6517 Bring Bring big teacher brother

HDU6518 Clumsy Keke

HDU6519 Enlarge it

HDU6520 Silly Keke

HDU6521 Party


 

HDU6511 Min-Max

题意:有一个长度为n的随机排列以及m个min、max操作。问最后一个操作的结果的期望 * n! 的结果。

思路:把一组数组按大于等于k与否用1\0表示,再按操作来一遍,如果结果为1,说明可行。而如果这个01数组有x个1,那么它对应的正常数组有x!*(n-x)!个。

#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
using namespace std;
bool a[1<<16][16];
ll fac[16];
bool b[1001];
int n,m;
struct op{
    bool oper,flagx,flagy;//oper表示是否max,flag表示是否数组a、b,
    int x,y;
}op[1001];
void pre()
{
    memset(a,0,sizeof(a));
    int x=1<<n;
    for(int i=0;i<x;i++)
        for(int j=1,t=i;j<=n;j++,t>>=1)
            a[i][j]=t&1;
}
void getfac()
{
    fac[0]=1;
    for(int i=1;i<=15;i++)
    {
        fac[i]=fac[i-1]*(ll)i;
    }
}
bool Find(int i)  //对a[i]数组做模拟运算
{
    for(int j=1;j<=m;j++)
    {
        if(op[j].oper)
        {
            if(op[j].flagx&&op[j].flagy) b[j]=max(a[i][op[j].x],a[i][op[j].y]);
            else if(op[j].flagx&&!op[j].flagy) b[j]=max(a[i][op[j].x],b[op[j].y]);
            else if(!op[j].flagx&&!op[j].flagy) b[j]=max(b[op[j].x],b[op[j].y]);
            else b[j]=max(b[op[j].x],a[i][op[j].y]);
        }
        else
        {
            if(op[j].flagx&&op[j].flagy) b[j]=min(a[i][op[j].x],a[i][op[j].y]);
            else if(op[j].flagx&&!op[j].flagy) b[j]=min(a[i][op[j].x],b[op[j].y]);
            else if(!op[j].flagx&&!op[j].flagy) b[j]=min(b[op[j].x],b[op[j].y]);
            else b[j]=min(b[op[j].x],a[i][op[j].y]);
        }
    }
    return b[m];
}
int getnum(int i)
{
    int ans=0;
    for(int j=1;j<=n;j++)
        if(a[i][j]) ans++;
    return ans;
}
int main()
{
    string str;
    char x,y;
    int p,q;
    getfac();
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        pre();
        ll ans=0;
        for(int i=1;i<=m;i++)
        {
            cin>>str>>x>>p>>y>>q;
            if(str=="max") op[i].oper=1;
            else op[i].oper=0;
            if(x=='a') op[i].flagx=1;
            else op[i].flagx=0;
            if(y=='a') op[i].flagy=1;
            else op[i].flagy=0;
            op[i].x=p;op[i].y=q;
        }
        for(int i=0;i<(1<<n);i++)
        {
            if(Find(i))
            {
                int cnt=getnum(i);
                ans+=fac[cnt]*fac[n-cnt];
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

HDU6512 Triangle

题意:给你n根棍子,问你是否有其中三根可以组成三角形。

思路:不能组成三角形的数至少构成斐波那契数列。故我们可以算出2的32次方对应第x个斐波那契数,那么当输入n>x时,必然输出YES,否则进行排序,判断是否有a[i]+a[i+1]>a[i+2]。

//第50个斐波那契数已经超过int的限度了。
//如果用三次循环和break也能通过。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
int main()
{
    int n;
    int a[5000005];
    while(cin>>n)
    {
        for(int i=0;i<n;i++) scanf("%d",&a[i]); //cin超时
        if(n>50) cout<<"YES"<<endl;
        else 
        {
            bool flag=0;
            sort(a,a+n);
            for(int i=0;i<n-2;i++)
                if(a[i]+a[i+1]>a[i+2])
                {
                    flag=1;
                    break;
                }
            if(flag) cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
        }
    }
    return 0;
}

HDU6513 Reverse it 

题意:有一个n行m列的卡牌阵,每个位置是0或1,0代表卡牌背面朝上,1代表卡牌正面朝下。每次可以选择一个小矩阵,把这个矩阵内所有卡牌翻转,问最后可以得到多少本质不同的卡牌阵。

HDU6514 Monitor

题意:在一个面积不超过n*m的矩形上,有p个矩形A,问之后的q个矩形B能否被之前的A全部覆盖。

思路:数据范围超大,用到了二维前缀和,所谓二维前缀和既是v[i,j]表示从(0,0)到(i,j)的面积

#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<algorithm>
#define ll long long
#define MAX 10000007
using namespace std;
int v[MAX];
int m,n;
void add(int i,int j,int k)
{
    if(i>m||j>n) return;
    v[(i-1)*n+j]+=k;
}
int query(int i,int j)
{
    if(i==0||j==0) return 0;
    return v[(i-1)*n+j];
}
void Print()
{
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=n;j++) cout<<v[(i-1)*n+j]<<' ';
        cout<<endl;
    }
}
int main()
{
    int k,x1,x2,y2,y1;
    while(cin>>m>>n)
    {
        memset(v,0,sizeof(v));
        cin>>k;
        while(k--)
        {
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            add(x1,y1,1);
            add(x2+1,y2+1,1);
            add(x1,y2+1,-1);
            add(x2+1,y1,-1);
        }
        //二维前缀和
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++)
                v[(i-1)*n+j]+=query(i-1,j)+query(i,j-1)-query(i-1,j-1);
        //Print();//确定某一点有无被覆盖
        for(int i=1; i<=n*m; i++)
            if(v[i]) v[i]=1;
        //再求前缀和
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++)
                v[(i-1)*n+j]+=query(i-1,j)+query(i,j-1)-query(i-1,j-1);
        cin>>k;
        while(k--)
        {
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            int tmp=query(x2,y2)+query(x1-1,y1-1)-query(x1-1,y2)-query(x2,y1-1);
            if(tmp==((x2-x1+1)*(y2-y1+1))) cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
        }
    }
    return 0;
}

HDU6515 Coding problem

题意:将字符串每个字符ASCII的二进制翻转码组成的字符串以每6个一组输出。

思路:模拟

#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<algorithm>
#define ll long long
#define p (i*8+j)/6
using namespace std;
int main()
{
    string a;
    int ans[400004];
    while(cin>>a)
    {
        memset(ans,0,sizeof(ans));
        int n=a.length();
        for(int i=0;i<n;i++)
            for(int j=0;j<8;j++,a[i]>>=1)
                ans[p]=(ans[p]<<1)+(a[i]&1);

        for(int i=0;i<(n/3*4);i++)
            cout<<ans[i]<<' ';
    }
    return 0;
}

HDU6516 Network

HDU6517 Bring Bring big teacher brother

HDU6518 Clumsy Keke

题意:给定一个立方堆的三视图,求它的体积(有多种可能则输出最大)。

思路:如果下面的代码不好理解的话,可以考一下切割,即建立一个v[100][100][100],初始为1,慢慢切割,最后统计。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<algorithm>
#define ll long long
#define p (i*8+j)/6
using namespace std;
int main()
{
    int x,y,z;
    while(cin>>x>>y>>z)
    {
        int ans=0;
        bool f[100][100],t[100][100],s[100][100];
        for(int i=0;i<x;i++)
            for(int j=0;j<y;j++) cin>>f[i][j];
        for(int i=0;i<y;i++)
            for(int j=0;j<z;j++) cin>>t[i][j];
        for(int i=0;i<z;i++)
            for(int j=0;j<x;j++) cin>>s[i][j];
        for(int i=0;i<x;i++)
            for(int j=0;j<y;j++)
                for(int k=0;k<z;k++)
                    if(f[i][j]&&t[j][k]&&s[k][i]) ans++;
        cout<<ans<<endl;
    }
    return 0;
}

HDU6519 Enlarge it

题意:输入一个字符矩阵,把它放大k倍输出。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<algorithm>
#define ll long long
using namespace std;
int main()
{
    int m,n,k;
    char a[100][100],b[1000][1000];
    while(cin>>m>>n>>k)
    {
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++)
                cin>>a[i][j];
        for(int i=0;i<m*k;i++)
        {
            for(int j=0;j<n*k;j++)
                cout<<a[i/k][j/k];
            cout<<endl;
        }
    }
    return 0;
}

HDU6520 Silly Keke

HDU6521 Party

题意:有n个人,开m次派对,每次派对每对人会相互认识对方。对于每一次派对,我们要求出新认识的pair的数量。

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值