zoukankan      html  css  js  c++  java
  • 洛谷3月月赛div2 题解(模拟+数学+贪心+数学)

    由于本人太蒻了,div1的没有参加,胡乱写了写div2的代码就赶过来了。

    T1 苏联人

    题目背景

    题目名称是吸引你点进来的。

    这是一道正常的题,和苏联没有任何关系。

    题目描述

    你在打 EE Round 1,发现第一题非常无聊。于是你不打了,去下国际象棋了。

    结果你发现,由于神秘力量的影响,你的棋子只剩下若干黑色的战车,若干黑色的主教和一只白色的国王了。

    由于你很无聊,所以你把一些黑色棋子放在了 8×88 imes 88×8 的棋盘上。

    由于你很无聊,所以你想知道,国王放在哪些格子是安全的。换句话说,有哪些格子不会被战车和主教攻击到。当然,国王不能放在已经有棋子的地方

    为了防止你无聊透顶而不知道国际象棋的规则,这里给出以下提示(如果你知道规则那么可以跳过):

    国际象棋中,战车可以横向、竖向移动,且格数不受限制。但不能越过其他棋子

    如图,黄色的格子为战车能走到(攻击到)的格子。

    国际象棋中,主教可以斜向移动,且格数不受限制。但不能越过其他棋子

    如图,黄色的格子为主教能走到(攻击到)的格子。

    简单来说,如果当前位置到目标位置的直线上存在其他棋子,则可以称为“越过了其他棋子”。

    如果目标位置是对方的棋子,那么移动到目标位置后,对方的棋子会被吃掉。

    更进一步地,你要找的所有位置,必须满足没有黑色棋子能一步走到。


    如果你还是没有读懂,可以结合样例进行理解。

    输入格式

    8 行,每行 8 个字符,表示棋盘的状态。

    其中 . 表示空位,R 表示战车,B 表示主教。

     

    ————————————————————————————————————————————————-

    根据题意模拟即可,数据比较水。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int a[9][9];
     4 int main()
     5 {
     6     for (int i=1;i<=8;i++)
     7         for (int j=1;j<=8;j++)
     8         {
     9             a[i][j]=1;
    10             char ch;cin>>ch;
    11             if (ch=='B') a[i][j]=3;
    12             else if (ch=='R') a[i][j]=2;
    13         }    
    14     for (int i=1;i<=8;i++)
    15         for (int j=1;j<=8;j++)
    16         {
    17             if (a[i][j]==0||a[i][j]==1) continue;
    18             if (a[i][j]==2)
    19             {
    20                 for (int k=j-1;k>=1;k--)
    21                     if (a[i][k]==2||a[i][k]==3) break;
    22                     else a[i][k]=0;
    23                 for (int k=j+1;k<=8;k++)
    24                     if (a[i][k]==2||a[i][k]==3) break;
    25                     else a[i][k]=0;
    26                 for (int k=i-1;k>=1;k--)
    27                     if (a[k][j]==2||a[k][j]==3) break;
    28                     else a[k][j]=0;
    29                 for (int k=i+1;k<=8;k++)
    30                     if (a[k][j]==2||a[k][j]==3) break;
    31                     else a[k][j]=0;
    32             }
    33             if (a[i][j]==3)
    34             {
    35                 for (int k=i-1,l=j-1;min(k,l)>=1;k--,l--)
    36                     if (a[k][l]==2||a[k][l]==3) break;
    37                     else a[k][l]=0;
    38                 for (int k=i+1,l=j+1;max(k,l)<=8;k++,l++)
    39                     if (a[k][l]==2||a[k][l]==3) break;
    40                     else a[k][l]=0;
    41                 for (int k=i+1;i+j-k>=1&&k<=8;k++)
    42                     if (a[k][i+j-k]==2||a[k][i+j-k]==3) break;
    43                     else a[k][i+j-k]=0;
    44                 for (int k=i-1;k>=1&&i+j-k<=8;k--)
    45                     if (a[k][i+j-k]==2||a[k][i+j-k]==3) break;
    46                     else a[k][i+j-k]=0;
    47             }
    48         }
    49     for (int i=1;i<=8;i++)
    50     {
    51         for (int j=1;j<=8;j++) 
    52         if (a[i][j]==1) cout<<1;
    53         else cout<<0;
    54         cout<<endl;
    55     }
    56     return 0;
    57 } 

    T2 迫害

    题目描述

    kkk 个人,X 要对这 kkk 个人进行迫害。

    kkk 个人,每一个人都拥有一个数字,分别从 111 至 kkk。

    X 拥有 n+mn+mn+m 个数字,这些数字为 nnn 个 111 和 mmm 个大小可由 X 决定的数字(每个数字定好之后不能更换)。

    X 能对这些人进行迫害,当且仅当他能用手中若干个数的加和等于被迫害人的数字,一次迫害就成功了(不会消耗数字)。

    由于 X 的权利极大,又十分邪恶,他想要从第 111 个人开始一个一个进行迫害行动。

    由于小 Z 也在这个被迫害的行列里,他十分的慌张,希望你来告诉他 X 能最多能从第一个人开始连续迫害多少个人。

    由于被迫害的人太多了,所以请将答案对 100000000710000000071000000007 取模。

    输入格式

    第一行两个整数 n,mn,mn,m,表示 X 有 nnn 个 111,有 mmm 个大小可自定的数。

    输出格式

    请你告诉小 Z,X 能迫害多少个人。

    --------------------------------------------------------------------------------------

    可以发现这样的规律:

    n=1

    1 2 4 8 16……为最佳方案数

    n=2

    1 1 3 6 12 24……为最佳方案数

    归纳得出方案总数为pow(2,m)*(n+1)-1,需要使用快速幂。

     1 #include<bits/stdc++.h>
     2 #define int unsigned long long
     3 using namespace std;
     4 int n,m;
     5 const int mod=1000000007;
     6 unsigned long long qcal(int a, int b) {
     7     int ans = 1, base = a;
     8     while (b != 0) {
     9         if (b & 1 != 0)
    10 {
    11             ans *= base;
    12             ans%=mod;
    13 }
    14             base *= base;
    15             base%=mod;
    16             b >>= 1;
    17             b%=mod;
    18     }
    19     return ans%mod;
    20 }
    21 signed main()
    22 {
    23     cin>>n>>m;
    24     unsigned long long ans=qcal(2,m)*(n+1);
    25     ans%=mod;
    26     printf("%lld",(ans-1)%mod);
    27     return 0;
    28  } 

    T3 代价

    题目描述

    给出一段序列,删数。代价为a[i-1]*a[i]*a[i+1]。求最小代价。

    输入格式

    第一行一个正整数 n。

    第二行 n 个正整数,第 i个数表示 a[i+1]

    输出格式

    一行一个正整数,表示最小的代价和。

    -----------------------------------------------------------------------------

    贪心比较显然,但关键是怎么贪?

    以样例为例:

    4

    19 26 8 17

    序列上实际是1 19 26 8 17 1

    既然让代价最小,那我们可以让序列从一端出去,即ans+=a[i]*a[i+1]。因为不管怎样,相邻的两个数必有一乘,乘1能将代价最小化。

    但实际上情况要复杂。序列中可能有无穷多个1。按照这种贪心策略,这时候的1是要分开处理的。所以我们不妨将两个1之间的序列单独处理。

    具体可以看代码。

     1 #include<bits/stdc++.h>
     2 #define int long long
     3 using namespace std;
     4 int ans,a[1000005],minn=0x3f3f3f3f,n,cnt;
     5 inline int read()
     6 {
     7     int x=0,f=1;char ch=getchar();
     8     while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
     9     while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    10     return x*f;
    11 }
    12 signed main()
    13 {
    14     n=read();
    15     a[0]=a[n+1]=1;
    16     for (int i=1;i<=n;i++){
    17         a[i]=read();
    18         minn=min(a[i],minn);
    19     }
    20     if (minn==1)
    21     {
    22         minn=0x3f3f3f3f;
    23         for (int i=0;i<=n+1;i++)
    24         {
    25             if (a[i]==1)
    26             {
    27                 ++cnt;
    28                 if (minn!=0x3f3f3f3f) ans+=minn,minn=0x3f3f3f3f;
    29                 continue;
    30             }
    31             minn=min(a[i],minn);
    32             if (a[i+1]!=1) ans+=1ll*a[i]*a[i+1];
    33         }
    34         ans+=cnt-2;
    35     }
    36     else{
    37         ans=minn;
    38         for (int i=1;i<n;i++) ans+=1ll*a[i]*a[i+1];
    39     }
    40     printf("%lld",ans);
    41     return 0;
    42 }

    T4 礼物

    原题描述

    -------------------------------------------------------------------------------------------------------

    我事先并不知道正解是什么,如果洛谷出题解了,我会仔细看正解的,我的程序很慢很慢。

    什么?证明?不存在的!我这种数学蒟蒻怎么会证明!

    通过对n<=100的数据进行打表我们可以发现,ans=从1到num所有质数的乘积之和(除了被标记的质数)-1;

    (其实是笔者手算了一大堆数据,现在感觉挺秃然的

    所以我们现在可以愉快地写代码了。

    你会惊奇地发现,全TLE了。

    所以这就要考验各位OIer的人品和卡常技巧了。

    1.八聚氧

    #pragma GCC optimize(3)
    #pragma GCC target("avx")
    #pragma GCC optimize("Ofast")
    #pragma GCC optimize("inline")
    #pragma GCC optimize("-fgcse")
    #pragma GCC optimize("-fgcse-lm")
    #pragma GCC optimize("-fipa-sra")
    #pragma GCC optimize("-ftree-pre")
    #pragma GCC optimize("-ftree-vrp")
    #pragma GCC optimize("-fpeephole2")
    #pragma GCC optimize("-ffast-math")
    #pragma GCC optimize("-fsched-spec")
    #pragma GCC optimize("unroll-loops")
    #pragma GCC optimize("-falign-jumps")
    #pragma GCC optimize("-falign-loops")
    #pragma GCC optimize("-falign-labels")
    #pragma GCC optimize("-fdevirtualize")
    #pragma GCC optimize("-fcaller-saves")
    #pragma GCC optimize("-fcrossjumping")
    #pragma GCC optimize("-fthread-jumps")
    #pragma GCC optimize("-funroll-loops")
    #pragma GCC optimize("-fwhole-program")
    #pragma GCC optimize("-freorder-blocks")
    #pragma GCC optimize("-fschedule-insns")
    #pragma GCC optimize("inline-functions")
    #pragma GCC optimize("-ftree-tail-merge")
    #pragma GCC optimize("-fschedule-insns2")
    #pragma GCC optimize("-fstrict-aliasing")
    #pragma GCC optimize("-fstrict-overflow")
    #pragma GCC optimize("-falign-functions")
    #pragma GCC optimize("-fcse-skip-blocks")
    #pragma GCC optimize("-fcse-follow-jumps")
    #pragma GCC optimize("-fsched-interblock")
    #pragma GCC optimize("-fpartial-inlining")
    #pragma GCC optimize("no-stack-protector")
    #pragma GCC optimize("-freorder-functions")
    #pragma GCC optimize("-findirect-inlining")
    #pragma GCC optimize("-fhoist-adjacent-loads")
    #pragma GCC optimize("-frerun-cse-after-loop")
    #pragma GCC optimize("inline-small-functions")
    #pragma GCC optimize("-finline-small-functions")
    #pragma GCC optimize("-ftree-switch-conversion")
    #pragma GCC optimize("-foptimize-sibling-calls")
    #pragma GCC optimize("-fexpensive-optimizations")
    #pragma GCC optimize("-funsafe-loop-optimizations")
    #pragma GCC optimize("inline-functions-called-once")
    #pragma GCC optimize("-fdelete-null-pointer-checks")

    下面是代码

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<bitset>//压位用的,不然内存会爆炸,笔者用int时内存达到了1G
     6 using namespace std;
     7 int prime[16252326],num;
     8 int n,m,c;
     9 int p[25];
    10 bitset<300000010>v;
    11 int main()
    12 {
    13     scanf("%d%d%d",&n,&m,&c);
    14     for (register int i=2;i<=n;++i)//您需要灵活优化线性筛素数,才能防止被3e8的数据卡掉
    15     {
    16         if (!v[i]){
    17             prime[++num]=i;
    18         }
    19         if((!(i&1))&&(i<<1)<=n){
    20             v[i<<1]=1;
    21             continue;
    22         }
    23         for(register int j=1;j<=num;j+=4){
    24             if(i*prime[j]>n)break;
    25             v[i*prime[j]]=1;
    26             if(!(i%prime[j]))break;
    27             if(j+1>num)break;
    28             if(i*prime[j+1]>n)break;
    29             v[i*prime[j+1]]=1;
    30             if(!(i%prime[j+1]))break;
    31             if(j+2>num)break;
    32             if(i*prime[j+2]>n)break;
    33             v[i*prime[j+2]]=1;
    34             if(!(i%prime[j+2]))break;
    35             if(j+3>num)break;
    36             if(i*prime[j+3]>n)break;
    37             v[i*prime[j+3]]=1;
    38             if(!(i%prime[j+3]))break;
    39         }
    40     }
    41     for(register int i=1;i<=m;i++){
    42         scanf("%d",&p[i]);
    43         if(p[i]==1){//1肯定不行,因为上来就出错,a3=3
    44             printf("-1
    ");
    45             return 0;
    46         }
    47     }
    48     sort(p+1,p+m+1);//这里排序是为了更好地去重
    49     int now=1;
    50     int ans=1;
    51     for(register int i=2;i<=num;++i){
    52         if(now<=m&&p[now]==i){
    53             while(now<=m&&p[now]==i)now++;
    54             continue;
    55         }
    56         ans=(1ll*ans*prime[i])%c;
    57     }
    58     printf("%d
    ",(ans-1+c)%c);
    59     return 0;
    60 }

    啊啊啊啊重复一遍我只是个蒟蒻,其实把这个代码发出来是为了给一点思路都没有的同学看的,咱别的不行,OI的基本操作咱还是要会的。

    顺带一提,这道题我提交了43次才通过,名副其实的毒瘤题目。

  • 相关阅读:
    Swap Nodes in Pairs
    Length of Last Word
    leetcode开篇
    数据备份crontab+pyhon
    hdu 1848 博弈 难题 取石子 三堆
    jd1338.c
    ubuntu 13.10上配置打印机
    运煤智力题
    【开发记录】RTMP推流协议互联网直播点播平台EasyDSS新增生成水印模块记录
    互联网视频直播点播分析平台EasyDSS配置公网IP后登录提示“服务不存在”问题排查过程介绍
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/12446176.html
Copyright © 2011-2022 走看看