zoukankan      html  css  js  c++  java
  • 20190226模拟

    -----电灯--------------

    有 n 个灯泡排成一列。每个灯泡可能是点亮或熄灭的。有一台操控灯泡的机器,每一次可以选择一段连续区间,让这段连续区间中熄灭的灯泡全部点亮,亮着的灯泡全部熄灭。但由于机器已经老化,仅能再使用一次了。

    你可以认为点亮的灯泡与熄灭的灯泡交替排列的样子(下面称这样的灯泡列为交替列)很好看。现在,你希望珍惜最后一次操控灯泡的机会,使得操控后这列灯泡中最长的交替列尽可能地长。

    例如这列灯泡若原本如下所示(○ 表示点亮的灯泡,● 为熄灭的灯泡):○ ○ ● ● ○ ● ○ ○ ○ ●

    如果选择第 4 个到第 7 个灯泡,则会变成如下的形式:○ ○ ● ○ ● ○ ● ○ ○ ●

    此时,最长的交替列为第 2 个到第 8 个灯泡,长度为 7。

    而如果仅选择第 8个灯泡,则会变成如下的形式: ○ ○ ● ● ○ ● ○ ● ○ ●

    此时,最长的交替列为第 4 个到第 10 个灯泡,长度也为 7。

    可以发现,此例中没有方法能使得最长交替列长度大于 7,则 7 即为答案。

    输入格式

    输入文件第一行一个正整数 n,表示灯泡的数量。 第二行包含 n 个数字,每个数字均为 0 或 1,依次代表序列中每个灯泡的初始状态。1 代表点亮,0 代表熄灭。

    输出格式

    输出一个整数,表示所有能得到的灯泡列中最长的交替列的长度

    Input 1:

    10

    1 1 0 0 1 0 1 1 1 0

    Output 1:

    7

    Input 2:

    5

    1 1 0 1 1

    Output 2:

    5

    提示与说明

    对于 30%的数据,1≤n≤500。

    对于 60%的数据,1≤n≤2000。

    对于 100%的数据,1≤n≤100000。

    _______________________________________________________________________________

    很显然,可以将每个交替序看成一体,一次肯定反转一整个交替序,使其与前一个与后一个相连,形成一个整体的交替序,找出最大的那个就可以了,时间复杂度O(N)

    但是!!!重点!!!要开long long!!!!!

    #include<cstdio>
    #define maxn 100010
    using namespace std;
    int n,a[maxn],st[maxn],l[maxn];
    int maxx;
    int main()
    {
             int i;
             scanf("%d",&n);
             for(i=1;i<=n;i++) scanf("%d",&a[i]);
             st[1]=1;
             l[1]=1;
             for(i=2;i<=n;i++)
             {
                       if(a[i]!=a[i-1])
                       {
                                st[i]=st[i-1];
                                l[st[i]]++;
                       }
                       else
                       {
                                st[i]=i;
                                l[i]=1;
                       }
             }
             i=1;
             while(i<=n)
             {
                       int now=l[i]+l[st[i-1]]+l[i+l[i]];
                       if(now>maxx) maxx=now;
                       i=i+l[i];
             }
             printf("%d",maxx);
             return 0;
    }

    ---比萨 -------------

    Kikok 得到了一块比萨,他迫不及待地想与妹妹 Kik 子和 koko 美一同享用它。

    比萨是一种圆形的食物。为了将它分给三个人,Kikok 需要沿着半径方向切三刀。可是,由于这个比萨太硬了,Kikok 只能沿着划好的刀痕把它切开。比萨上一开始有 n 条刀痕,沿顺时针将它们按照从 1 到 n 的顺序标号

    当 1 leq i leq n 时,第 i 条刀痕与第 i+1 条刀痕之间的部分大小为 a_i;第 n 条与第 1 条刀痕之间的部分大小为 a_n

    因为怕妹妹们哭闹,在比萨分成三块后,Kikok 准备让妹妹们拿较大的两块,自己拿最小的一块.可是,Kikok 实在太喜欢比萨了,他想吃地尽可能多,也就是让切出的比萨中最小的一块尽可能地更大。那么,Kikok 最多能吃到多少比萨呢?

    输入格式

    输入文件第一行包含一个整数 n,表示比萨上刀痕的数量。

    接下来 n 行,其中第 i 行包含一个整数 a_i,依次表示相邻两条刀痕之间的部分的大小。

    输出格式

    输出一行一个整数,表示最小的一块比萨的最大大小。

    Input 1:

    6

    1 5 4 5 2 4

    Output 1:

    6

    对于 10%的数据,n≤100。

    对于 30%的数据,n≤400。

    对于 60%的数据,n≤8000。

    对于 100%的数据,3≤n≤100000, 1≤ai≤1000000000。

    _______________________________________________________________________________

    重点!!!!开longlong!!!!!

    O(n)的dalao算法:

    三个指针,计算将序列分为3分,前缀和计算每次比萨的大小,每次将最小的比萨扩大,规定每次指针只能向右移动

    因为是序列本来是环,所以指针超过n时返回到位置1

    移动3N次一定可以枚举所有可能

    #include<cstdio>
    #include<iostream>
    #define maxn 100010
    using namespace std;
    long long n,a[maxn],minn,sum[maxn];
    int main()
    {
        scanf("%lld",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        int t1=1,t2=2,t3=3;
        for(int i=1;i<=3*n;i++)
        {
            if(t2>t3) swap(t2,t3);
            if(t1>t2) swap(t1,t2);
            long long ans1=sum[t2]-sum[t1];
            long long ans2=sum[t3]-sum[t2];
            long long ans3=sum[n]-sum[t3]+sum[t1];
            long long pp=min(ans1,min(ans2,ans3));
            if(pp>minn) minn=pp;
            if(pp==ans2)
            {
                 t3++;
                 if(t3>n) t3=1;
            }
            else if(pp==ans1)
            {
                t2++;
                if(t2>n) t2=1;
            }
            else if(pp==ans3)
            {
                t1++;
                if(t1>n) t1=1;
            }
        }
        printf("%lld",minn);
        return 0;
    }

    --------断层-----------------

    不会:)

    将坐标轴顺时针旋转45度,使每次操作都变成竖直左边下移或或水平上边右移

    旋转后坐标由(x,y)变为(x-y,x+y),单位长度变为原来的根号2倍

    旋转后每行每个点的原始深度都呈升序,移动后也不改变

    结构体里写线段树的神奇操作

  • 相关阅读:
    Hash碰撞 & 拒绝服务漏洞
    Java: 在不同windows主题下,JFrame窗口设置最佳高度的解决方案
    java: 关于从jar中读取资源遇到的问题getClass().getResource(...)
    Windows 服务程序、窗口界面、桌面交互、与远程桌面
    MySQL用户与权限管理
    Linux 用户与用户组
    书单整理
    2013年个人工作与学习总结
    Raphaël.js学习笔记
    Ant学习笔记(2) 在Eclipse中使用Ant
  • 原文地址:https://www.cnblogs.com/QAQq/p/10438217.html
Copyright © 2011-2022 走看看