又考一次,又寄啦

在游戏中,你将得到一个长度为 n 的序列 a 1 ...a n 和一个棋子,一开始棋子放在 a 1 处,你的得分为
a 1 。接下来你可以做出 n 次选择,以使自己的得分最大化。
i 次选择,你可以决定是否使棋子前进 2 i 1 的距离。若前进,则你的得分加上移动后位置上的数
字;若不前进,则什么也不会发生。
特别地,如果走到了序列外面(前进的距离大于等于 n ),将把已经获得的分数清零,即总分 0 分。
请你做出最恰当的选择,并输出最高可能的得分
由于每个数的二进制分解是唯一的,所以走到一个点的方法是唯一的,所以可以枚举所有点,计算出终点为此点时的得分,比较得到所有得分中最大的就是答案

const long long N=1000005;
long long n,aa,ans,xi=0;
long long a[N],g[N];
int m;
int zh(int b)  //  写了一个函数,把点的下标转成二进制数求他的位数
{
    int i=0;
    while(b!=0)
    {
        ++i;
        b/=2;
    }
    return i;
}
long long j(int b)  //  再写一个函数算该店的得分,某点的得分等于该点下标减去他的二进制最高位再加上该店的数
{
    //cout<<b<<endl;
    if(b==0) return ans=a[0];
    else{
        ans=g[(b-(1<<(m-1)))]+a[b];  //  
        return ans;
    }
}
int main()
{
    scanf("%lld",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%lld",&aa);
        a[i]=aa;
    }
    for(int i=0;i<n;i++)
    {
        m=zh(i);  //  m是二进制最高位
    //    printf("%d\n",m);
        g[i]=j(i);
//        cout<<i<<' '<<g[i];
        if(xi<g[i]) xi=g[i];
    }
    if(xi>0) printf("%lld",xi);
    else printf("0");
    return 0;
}
f 想在一张格子纸上写一段话。可是小 f 不知道还能不能写的下。
这张长方形纸有 n m 列,其中有一些行和一些列已被涂黑,而其余地方是干净的。
f 想要写的话一共包含 k 个字,他希望每个格子里写一个字;不能写在涂黑的格子里,也不能被
涂黑的格子分割成几部分。
请问这张纸还能写下小 f 的话吗?
第一行一个数字 T 表示测试组数
接下来输入 T 组测试数据,每一组测试数据形如:
第一行四个整数 n, m, p, q, w ,表示总行数、总列数、涂黑的行数、涂黑的列数,小 f 想要写下的字数
第二行从小到大 p 个整数,表示写满字的行的编号
第三行从小到大 q 个整数,表示写满字的列的编号
因为是整行涂黑,所以所有空白部分都是矩形,所以最大空白行距乘以最大空白列距就是最大空位,这样就可以开两个数组,将行和列分别计算再相乘,不用开二维数组,会爆内存。

const long long N=1000005;
int t,n,m,p,q,x,y;
long long w,da1=-3,da2=-3;  //  注意数据范围是1e6,所以w最大是1e6*1e6,要开long long
int h[N],l[N];
int zdh,zdl;
int main()
{
    scanf("%d",&t);
    for(int i=1;i<=t;i++)
    {
        zdh=0;zdl=0;da1=-3;da2=-3;
        memset(h,0,sizeof(h));
        memset(l,0,sizeof(l));    //  总共有t组数据,所以每次数组要清零
        scanf("%d%d%d%d%lld",&n,&m,&x,&y,&w);
        for(int j=1;j<=x;j++)
        {
            scanf("%d",&p);
            h[p]=1;   //  被涂黑的就标记成1
        }
        for(int j=1;j<=y;j++)
        {
            scanf("%d",&q);
            l[q]=1;
        }
        for(int j=1;j<=n;)
        {
            while(h[j]==0&&j<=n)  //  如果是0,就是空白处,就一直++直到不是0
            {
                zdh++;
                j++;
            }
            j++;  //while外面也要++,不然会死循环
            if(da1<zdh) da1=zdh;zdh=0;  //  找出最大的空白行距,然后把这次计算的行距归零
        }
        for(int j=1;j<=m;)
        {
            while(l[j]==0&&j<=m)
            {
                zdl++;
                j++;
            }
            j++;
            if(da2<zdl) da2=zdl;zdl=0;
        }
        //printf("%d %d %d\n",da1,da2,da1*da2);
        if(da1*da2>=w) printf("Y\n");
        else printf("N\n");
    }
    return 0;
}
世界可视为 N N 个城市排列成的方阵,其中有 M 个重要城市。小 c 想在某一个重要城市 F 中引
爆鲜花炸弹,这会让以 F 为中心,边长为 d 的正方形所覆盖的所有城市开满鲜花。
经过粗略计算,小 c 发现想让所有城市开满鲜花所需的成本过于巨大,于是他觉得只要所有重要城
市都开满鲜花就可以了。
然而,小 c 发现即使只让重要城市开满鲜花也是很困难的一件事,这次他觉得有至少一半的重要城
市能够开花就足够了。
c 想知道需要制作多大的炸弹,但他算不出来。请你告诉他想要达成目标所需的最小的 d
请将城市视为方格而非两条线的交点。边长为 1 的正方形只覆盖这个城市本身,边长为 3 的正方形
将覆盖以引爆点为中心的 3 × 3 个城市。
这个正方形可以超出世界边界,超出部分不产生影响。
Input
第一行两个数字 n, m
接下来 m 行,每行两个数字 x, y 表示在第 x 行第 y 列坐落着一个重要城市,坐标范围均为 1 n
Output
一个数字表示所需的最小的正方形的边长 . 由于正方形的中心必定位于一个城市,它的边长一定是个 奇数

const int N=1505;
int n,d,x,y,ans,p,q,da=10000;
int xx[N],yy[N];
double m,mm;
long long z[N][N];   //  数组不能太大,不然就爆内存了
int f(int a,int b)
{
    ans=0;
    p=a-d/2;
    q=b-d/2;
    for(int i=1;i<=m;i++)
    {
        if(xx[i]>=p&&xx[i]<=p+d-1&&yy[i]>=q&&yy[i]<=q+d-1) ans++;  //  扫过所有重要城市,看是否在爆炸范围内,如果在就加一
    }
    return ans;
}
int main()
{
    scanf("%d%lf",&n,&m);
    mm=ceil(m/2);  //  至少覆盖一半重要城市,向上取整,注意开double
    memset(z,0,sizeof(z));
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            z[i][j]=0;
        }
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        xx[i]=x;  //  开两个数组把横纵坐标存起来
        yy[i]=y;
        z[x][y]=1;  //  有重要城市的点设成1
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            d=1;  //  注意每次初始化边长为1
            if(z[i][j]==1) 
            {
                while(f(i,j)<mm)  //  以重要城市为中心,边长为1开始,看能否覆盖到足量城市,不能就把边长加2
                {
                    d+=2;
                    f(i,j);
                }
                if(f(i,j)>=mm)
                {
                    if(da>d) da=d;  //  记录下最小的能达到要求的边长
                }
            }
        }
    }
    printf("%d\n",da);
    return 0;
}
q 是个时空管理员,他有一台监视时间的设备。这台设备上有 12 个表盘,第 i 个表盘上有 i 个刻
度,分别标有 0 , 1 , 2 ...i 1 ,经过一秒时间,所有表盘的指针都会移动恰好一个刻度。小 q 就是用这样一
台机器监视着时间流动的。
在某个时间,小 q 把所有表盘都复位到了 0 . 过了不知道多少时间,他又看了一眼表盘,并记住了那
一瞬间 12 个表盘的示数。小 q 想确认已经过去了多久,请你告诉他,以秒为单位。如果有多种可能性,
输出数值最小的一种,可以为 0
如果表盘的示数情况不可能存在,说明小 q 要被炒鱿鱼了,请输出 ”gg”
思路比较重要,代码很好写,正确做法是直接枚举答案,然后逐个检查是否符合 ans a i mod i 即可。
#include<bits/stdc++.h>
using namespace std;
int tt,ans,da=1000009;
int t[13],shu[13];
bool tf;
int main()
{
    for(int i=1;i<=12;i++)
    {
        scanf("%d",&tt);
        t[i]=tt;  //  t数组是输入的表盘示数
    }
    for(int i=0;i<=1000000;i++)  //  从零开始枚举时间,一直到最大时间限制
    {
        tf=true;  //  初始是true
        for(int j=1;j<=12;j++)
        {
            shu[j]=i%j;  //  shu数组是当前时间下表盘的示数
            if(shu[j]!=t[j]) tf=false;  //  有一个表盘不符合就是false
        }
        if(tf==true&&da>i) da=i; //  记录下最小时间
    }
    if(da!=1000009) printf("%d",da);
    else printf("gg");  //  如果没有符合的就输出gg
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值