牛客寒假算法基础集训营3 非官方题解

附官方题解链接


A. 处女座与线性代数

链接:https://ac.nowcoder.com/acm/contest/329/A
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述
众所周知,处女座是数学大师。他定义了k维空间里的处女座点。
对于给出的k维度空间上N个点,处女座点满足:
对于这个点P和空间里任意其他两个点
P1、P2,有dot(PP1,PP2)<0。
现在给你一个k维空间和这N个点,请求出这里面所有的处女座点。

Hint:
dot(A,B)表示两个向量的点乘(内积)。两个向量
A={a1,a2,⋯,an}和B={b1,b2,⋯,bn}的点乘(内积)定义为:
dot(A→,B→)=a1∗b1+a2∗b2+⋯+an∗bn。

输入描述:
输入数据第一行包含一个整数T,表示用例组数。
对于每组用例,第一行两个整数 N,k。
接下来 N 行,每行k个整数,表示每个点的坐标。

输出描述:
对于每一组数据,先输出一个整数ans,表示处女座点的个数。
接下来ans行,每行k个数,表示每个处女座点的坐标。
如果有多个点满足条件,则按照输入数据中出现的顺序进行输出。

示例1

输入
1
3 2
0 0
1 1
-1 -1

输出
1
0 0

备注:
3≤N≤104
1≤k≤10
T≤100
对于每一个点,保证每一维坐标的绝对值在10^9以内


emmmm这个题我纯粹就是玄学过题法,建议去看std
显然暴力枚举每个点,判断是否是处女座点,需要O(n)的枚举和每个点O(n²)的判断,所以暴力复杂度为O(n³)
嗯所以没写暴力,不过虽然估计出来的复杂度那么高,实际上的执行时间可能很短。因为推复杂度的时候没考虑一个结论:处女座点最多只有一个(证明请见官方题解
然后肯定是想从复杂度上优化(???其实实际上并没有优化到看上去能过)
一个直观感受就是,处女座点的个数不会很多(虽然我当时没有想到是唯一的)
另一个经验是,对于O(n)的枚举,可以通过分治思想优化到O(logn)
所以我就写了个分治的代码。大致思想是,把点分成两份,在每份中找那一份中的处女座点,那么最终的处女座点一定是在这些点之间。然后再枚举判断每个点是否满足条件即可(因为本来就是个玄学方法所以细节也不再过多赘述了)。这样估计出来的复杂度是O(n²logn)
听到这个复杂度可能觉得还是过不去吧。但是我比赛的时候并没有想那么多吧emmmm反正就写出来了,然后就AC了
事后结合题解再想想,因为处女座点只有一个,所以我的分治过程中很大一部分的分治结果都是空集,所以虽然看起来复杂度有那么高,实际上的运行时间远远达不到这个数量级。(嗯这是为我的AC找借口)
所以还是建议大家去看std的证明,比我的玄学过题法好多了。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4 + 5;
const int maxk = 11;
int n, k;
struct Node {
    long long a[maxk];
    Node operator - (const Node& b) {
        Node ans;
        for(int i = 1; i <= k; i++)
            ans.a[i] = a[i] - b.a[i];
        return ans;
    }
    long long operator * (const Node& b) {
        long long ans = 0;
        for(int i = 1; i <= k; i++)
            ans += a[i]*b.a[i];
        return ans;
    }
} p[maxn];
vector<int> query(int l, int r) {
    vector<int> ans;
    if(l == r) {
        ans.push_back(l);
        return ans;
    }
    int mid = l+r >> 1;
    vector<int> ql = query(l, mid);
    vector<int> qr = query(mid+1, r);
    for(int x : ql) {
        bool flag = true;
        for(int i = l; i <= r && flag; i++) {
            if(i == x) continue;
            for(int j = max(mid+1, i+1); j <= r && flag; j++) {
                if(j == x) continue;
                if((p[i]-p[x])*(p[j]-p[x]) >= 0)
                    flag = false;
            }
        }
        if(flag) ans.push_back(x);
    }
    for(int x : qr) {
        bool flag = true;
        for(int i = l; i <= mid && flag; i++) {
            if(i == x) continue;
            for(int j = i+1; j <= r && flag; j++) {
                if(j == x) continue;
                if((p[i]-p[x])*(p[j]-p[x]) >= 0)
                    flag = false;
            }
        }
        if(flag) ans.push_back(x);
    }
    return ans;
}
int main() {
    int T; scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= k; j++)
                scanf("%lld", &p[i].a[j]);
        vector<int> ans = query(1, n);
        printf("%d\n", ans.size());
        for(int i : ans) {
            for(int j = 1; j <= k; j++)
                printf("%d ", p[i].a[j]);
            printf("\n");
        }
    }
    return 0;
}

B. 处女座的比赛资格

链接:https://ac.nowcoder.com/acm/contest/329/B
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述
处女座想出去比赛,但是又不知道学校能不能给到足够的经费。然而处女座是大众粉丝,有着很好的人缘,于是他找了一个在学校管经费的地方勤工俭学偷来了一份报销标准。
由于处女座是万人迷,所以他在中间途径的每一条线路上都会发生一些故事,也许是粉丝给他发了一个200元的微信红包,也许是和他的迷妹一起吃饭花了500元。
而经费负责人也实地考察了每一条路线,在每一条路上,也许是天降红包雨,也许是地生劫匪。每一条路上都有属于自己的奇遇。
而经费负责人也只能根据他的故事决定这一路批下来多少经费。他会找出从宁波到比赛地的最小花费,并以此作为标准给处女座打比赛。而处女座也会选择对他来说最小花费的路线,来节省使用。
处女座想知道,最终的经费是否够用,如果够还会剩下来多少钱。如果不够,他自己要自费掏出多少钱。(当然处女座和经费管理人都具有旅途中无限信贷额度,所有收入支出会在旅行结束后一起结算。)

输入描述:
输入文件第一行包含一个整数T,表示处女座要参加的比赛场数。
对于每一场比赛,第一行包含两个整数N,M,分别表示旅行中的站点数(其中宁波的编号为1,比赛地的编号为N)和线路数。
接下来M行,每一行包含5个整数u,v,c,cnz,jffzr,分别表示从u到v有一条单向的线路,这条线路的票价为c。处女座搭乘这条线路的时候,会得到cnz元(如果为负即为失去-cnz元);经费负责人搭乘这条线路的时候,会得到jffzr元(如果为负即为失去-jffzr元)。
行程保证不会形成环,并保证一定能从宁波到达比赛地。

输出描述:
对于每一场比赛,如果经费负责人给出的经费绰绰有余,则先在一行输出"cnznb!!!",并在下一行输出他可以余下的经费;如果处女座的经费不够用,则先在一行输出"rip!!!",并在下一行输出他需要自费的金额;如果经费负责人给出的经费正好够处女座用,则输出一行"oof!!!"。(所有输出不含引号)

示例1

输入
1
3 3
1 2 300 600 -600
2 3 100 -300 1
1 3 200 0 0

输出
cnznb!!!
100

说明
处女座先走第一条路再走第二条路到达,总花费100元,经费负责人走第三条路,花费200元,处女座经费剩余100元

备注:
T ≤ 10 T≤10 T10
2 ≤ N ≤ 105 2≤N≤105 2N105
1 ≤ M ≤ 2 ⋅ 1 0 5 1≤M≤2⋅10^5 1M2105
1 ≤ u , v ≤ N 1≤u,v≤N 1u,vN
0 ≤ c ≤ 109 0≤c≤109 0c109
− 1 0 9 ≤ c n z , j f f z r ≤ 1 0 9 −10^9 ≤ cnz,jffzr ≤ 10^9 109cnz,jffzr109


这是个有向无环图(DAG)上的最短路问题,理论上是个很简单的问题,但是我写TLE了。emmmm等我之后补题A了再补代码
大致分析跟std差不多,单源最短路算法只有几种,BFS(已知终点可以用),dijkstra,bellman-ford,SPFA。

  1. 一般最短路不会考虑BFS的,就算满足条件(虽然我觉得写个BFS说不定也能过)。
  2. 因为有负权边,所以dijkstra就不能用了(也有一种玄学dijkstra处理负权边的方法,就是假设把每条边加上一个权值,使得所有边都非负,并且计算最短路权值的过程中要同时记录短路中结点个数,最后将那个自己假想的权值减去,不过对于这个题目的数据范围来说这种玄学方法可能在这题不适用)
  3. SPFA(我用SPFA不熟练,可能跟不同dalao的板子又不同)要求开出二维数组储存 d [ i ] [ j ] d[i][j] d[i][j],即从第i个点到第j个点的距离,这里显然开不出这个数组
  4. 所以最后只有一个bellman-ford了,我比赛的时候确实也是写的bellman-ford,不过可能是因为自己写的太丑了,所以接了无数发TLE之后心态崩了,代码也被我改得不成人样了所以就不发了。
  5. 所以最终的正确答案我觉得应该就是bellman-ford了,std中虽然没有明确说是用的bellman-ford,但是他给出的dp方程恰好就是bellman-ford的dp方程,所以我猜就是bellman-ford吧。不过话不能说死emmmmmm也有可能是直接背我第一个忽视的BFS。emmmmmm还是等我之后补题AC之后再回来补代码吧.

C. 处女座点名

链接:https://ac.nowcoder.com/acm/contest/329/C
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述
处女座觉得自己手上的经费可能不太够,于是决定给牛逼学生们带家教。
一天他去上课用自己的火眼金睛感觉教室里有一个学生没有来,于是他就叫学生们报出自己的学号。
已知这个班上的学号是从1开始连续编号的,处女座告诉你这个班上有多少人,想问问你到底是谁没有来。

输入描述:
输入数据共两行,第一行为一个整数N,表示班上的学生数量。
第二行为一行N-1个整数,表示已经来的学生的学号,按升序给出。

输出描述:
输出一个整数,为没有来的学生的学号。

示例1

输入
3
1 3

输出
2

备注:
2 ≤ N ≤ 200 , 000 2≤N≤200,000 2N200,000


签到题
emmmm我写的时候没注意到说是说是升序emmmm所以写成了这个样子。。不过怎么写应该都行吧。。。
还是那句话。。这都不会的可以回去从语言开始学起了

#include<bits/stdc++.h>
using namespace std;
int main() {
    long long n; cin>>n;
    long long ans = (n*(n+1))>>1;
    while(--n) {
        long long t; cin>>t;
        ans -= t;
    }
    cout<<ans<<endl;
    return 0;
}

D. 处女座的训练

链接:https://ac.nowcoder.com/acm/contest/329/D
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述
处女座靠着自己的家教本领赚够了去比赛的钱,于是开启了疯狂训练。在每个夜深人静第二天不收作业的夜晚,他都会开始刷题。
"今日又是一个刷题的夜晚。"他挑选了n道题开始刷,而题太多,刷不掉,理还乱(呜呜)、自己没有解决的题目每分钟都会给他带来bi的疲倦值,而解决每一道题目都需要花费ai分钟的时间。
当然,处女座一般都是考虑清楚了再写题的,所以他在写题的时候都会精神抖擞,也就是说,当前正在写的那一题并不会给他带来任何疲劳。
为了迎接后天要收的作业和明天要遇到的小姐姐,他想让今晚的刷题尽可能的轻松,那请你帮他找出最小所需要的疲倦值吧。

输入描述:
输入数据共包括n+1行,第一行包括一个n表示处女座今晚打算训练的题的数量。
接下来n行,每行包括两个整数ai,bi,分别表示处女座刷掉本题要花费的时间和本题每分钟会带来的疲倦值。

输出描述:
一行包括一个整数,表示处女座今晚训练会产生的最小疲倦值。

示例1

输入
6
6 1
4 5
4 3
6 2
8 1
2 6

输出
86

说明
先做第6个题,增加(1+5+3+2+1)*2= 24 点疲倦值,再做第2个题,增加28点疲倦值,随后依次是第3,4,1,5道题,增加16,12,6点疲倦值。总共的疲倦值是24 + 28 + 16 + 12 + 6 = 86点。

备注:
2 ≤ N ≤ 1 0 5 . 2≤N≤10^5. 2N105.
2 ≤ a i ≤ 4 ⋅ 1 0 6 . 2≤a_i≤4⋅10^6. 2ai4106.
1 ≤ b i ≤ 1000 1≤b_i≤1000 1bi1000


这种题目读完就知道贪心orDP,而且这题显然是贪心
那么这种贪心必然是要将题目按照某种规律排序,然后从前到后依次做
首先尝试按b值从大到小排序,若b相同,则按a从小到大排序,然后得到1wa
然后按照b/a值从大到小排序,若b/a相同,则按b从大到小排序,然后AC
至于怎么证明,我想了一下,并不是那么好证。但是知道这题是贪心之后再想贪心策略,还是很容易想到这种性价比排序的。因为:
如果考虑只有2个题目的情况,设其所需时间和积累的疲倦值分别为 a 1 , b 1 , a 2 , b 2 a_1,b_1,a_2,b_2 a1,b1,a2,b2
那么如果先做第一个题,总共积累的疲倦值为 a 1 × b 2 a_1 \times b_2 a1×b2,如果先做第二个题,总共积累的疲倦值为 a 2 × b 1 a_2 \times b_1 a2×b1,即当 a 1 × b 2 < a 2 × b 1 a_1 \times b_2 < a_2 \times b_1 a1×b2<a2×b1时先做第一题,反之先做第二题,将其变形可得:当 b 2 a 2 < b 1 a 1 \frac{b_2}{a_2} < \frac{b_1}{a_1} a2b2<a1b1时先做第一题。所以只有两个题目的时候必然是先做b/a值大的那个
既然是贪心题,那么贪心策略对任意的n应该都是一样的(少数特例除外),显然n=2不算特例吧emmmm所以这题的贪心策略就出来了。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
struct Node {
    long long a, b;
    bool operator < (const Node& node) const {
        return 1.0*b/a > 1.0*node.b/node.a
            || (1.0*b/a == 1.0*node.b/node.a
                && b > node.b);
    }
} p[maxn];
int main() {
    int n; scanf("%d", &n);
    long long sum = 0;
    for(int i = 1; i <= n; i++) {
        scanf("%d%d", &p[i].a, &p[i].b);
        sum += p[i].b;
    }
    sort(p+1, p+n+1);
    long long cost = 0;
    for(int i = 1; i <= n; i++) {
        sum -= p[i].b;
        cost += sum*p[i].a;
    }
    cout<<cost<<endl;
    return 0;
}

E. 处女座和小姐姐

链接:https://ac.nowcoder.com/acm/contest/329/E
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述
既然昨天晚上处女座已经训练了,明天才要交作业,那今天就是平淡无奇要上课的一天了。
然而处女座也想自己的小姐姐了,可是这节课是老师安排座位,处女座坐在(1,1),而小姐姐坐在(n,m)。他们之间只能通过传纸条的方式来交流感情。对于处女座而言,他上课不想过度分心,因此并不想传纸条,只在那里趁机折千纸鹤。
老师上课喜欢用"开火车"的方式让大家轮流回答问题,显然处女座作为(1,1)位,会被第一个叫起来回答,之后老师将依次叫起(2,1),(3,1),….(n,1),(n,2),(n−1,2)⋯(1,2),⋯的人起来回答问题,每个人回答问题需要1秒。处女座在自己回答完以后会以每秒1个千纸鹤的速度折叠,在小姐姐开始回答问题的时候停止折叠。
处女座想知道,他这节课一共要折多少个千纸鹤?

输入描述:
输入文件包含T+1行,第一行包含一个整数T,表示用例组数。
接下来T行,每行包含两个整数n,m表示小姐姐的位置和教室的大小。

输出描述:
对于每一组用例,用一行输出一个整数,表示处女座要折的千纸鹤的个数。

示例1

输入
1
3 3

输出
7

备注:
2 ≤ n , m ≤ 1 , 000 2≤n,m≤1,000 2n,m1,000


这题也算是签到题吧emmmm不懂为什么还是那么多人想不通
相当于一个n行m列的方格,如果m是奇数,那么按照轨迹一定会把所有人都提问过之后才能问到(n,m),所以答案是nm-2,如果m是偶数,那么(n,m)是最后一列的第一个回答者,也就是说前m-1列的人都被提问过之后,马上就会提问(n,m),所以答案是n(m-1)-1
如果还不理解可以评论我

#include<bits/stdc++.h>
using namespace std;
int main() {
    int T; scanf("%d", &T);
    while(T--) {
        int n, m; scanf("%d%d", &n, &m);
        if(m&1) printf("%d\n", n*m-2);
        else printf("%d\n", n*(m-1)-1);
    }
    return 0;
}

F. 处女座和小姐姐(二)

没做这题,留题留坑,请见官方题解
链接:https://ac.nowcoder.com/acm/contest/329/F
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述
课上处女座成功将纸条传给了小姐姐,约下午和小姐姐一起逛街。他们坐在公交车上一起欣赏窗外的广告牌,每一个广告牌都有一个编号,而处女座的视野范围是有限的,每次只能看到连续的p个广告牌。由于处女座是数学大师,他用O(1)的时间算出来了他看到的广告牌编号的积mod P的值并记录了下来,直到坐车到了商场。
商场里有定制手环的地方,他可以定制一个长度为k的手环,但是选号是收费的,而处女座把家教挣来的钱都用于外出打比赛了,于是他决定自己挑号。
他把之前路上记下来数字按先从左往右,再从上到下的顺序排成一个n*m的矩阵,他想从中选出一条长度为k的路径,使得路径上的数在mod k的意义上各不相同(每个点只和他的上下左右相邻),从而作为他选的号码。
现在处女座想知道,他有多少条路径可以选择(不忽视顺序,(2,2)->(2,1)和(2,1)->(2,2)会被视为两条路径)。

输入描述:
输入数据共包括两行,第一行包括四个整数n,m,p,P,k,其中p为处女座一次能看到的连续广告牌的数量,其他字母含义如描述所示。
第二行包括四个整数 a 0 , x , y , z a_0,x,y,z a0,x,y,z,对于每个广告牌而言,他的编号是 a i = x ∗ a i − 12 + y ∗ a i − 1 + z ai=x∗a_i−12+y∗a_i−1+z ai=xai12+yai1+z。广告牌从
a 1 a_1 a1开始到 a n ∗ m + p − 1 an∗m+p−1 anm+p1为止。

输出描述:
一个整数,表示可以选择的路径数量。

示例1

输入
2 2 1 2 2
1 0 1 1

输出
4

说明
a 1 = 2 , a 2 = 3 , a 3 = 4 , a 4 = 5 a_1=2,a_2=3,a_3=4,a_4=5 a1=2,a2=3,a3=4,a4=5
所以2*2的矩阵是
( 0 1 0 1 ) \begin{matrix} 0 & 1\\ 0 & 1 \end{matrix}) 0011)
因此可行方案有(1,1)->(1,2),(1,2)->(1,1),(2,1)->(2,2),(2,2)->(2,1)共4种

备注:
1 ≤ n , m ≤ 20 1≤n,m≤20 1n,m20
1 ≤ k ≤ m i n ( 20 , n ∗ m ) 1≤k≤min(20,n∗m) 1kmin(20,nm)
1 ≤ p ≤ 106 1≤p≤106 1p106
1 ≤ A 0 , P , X , Y , Z ≤ 1 , 000 , 000 , 000 1≤A_0,P,X,Y,Z≤1,000,000,000 1A0,P,X,Y,Z1,000,000,000


G. 处女座和小姐姐(三)

链接:https://ac.nowcoder.com/acm/contest/329/G
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述
经过了选号和漫长的等待,处女座终于拿到了给小姐姐定制的手环,小姐姐看到以后直呼666!
处女座其实也挺喜欢6这个数字的,实际上他做手环的时候选取的k=6。所以他对于包含数码6的数字极其敏感。每次看到像4567这样的数字的时候他的心就像触电了一样,想起了小姐姐。
现在你要给处女座展示一系列数字,你想知道他的内心会激动多少次。对于同一个数字,他最多只会激动一次,即如果这个数是66666,他还是只会激动一次。

输入描述:
一行包括两个数字l,r,表示你给处女座展示的数字范围为[l,r]。

输出描述:
一行一个整数,表示处女座内心激动的次数。

示例1

输入
10 20

输出
1

备注:
0 ≤ l ≤ r ≤ 1 0 18 0≤l≤r≤10^{18} 0lr1018


emmmm这也算是个经典数学问题了
以前做过一个类似的题目,先从那个题目讲起可能比较好理解
原题是:从1开始的所有自然数1, 2, 3, 4,… 中,删掉含有数字2,3,5,7的数,变成1,4,6,8,9,10,11,14,16,18,19,30…
问新序列中的第k个数是多少
首先我们要把0,1,2,…,9这些数字看成符号,因为这里有10个符号,所以叫作十进制数,这10个符号替换成其他的任何符号,比如将用!替换1,@替换2,仍然不影响十进制的使用,此时1234就会写成!@34
现在要将其中的4个符号删掉,就相当于原来的10进制数变成了6进制数,删掉2之后,原来的符号3就称为了第二个符号,这个符号就不再代表我们思想中理解的三(他不再是第三个符号),而是我们理解中的二(他是第2个符号)。
十进制中的第17个数,就是把17表示成十进制(尽管现在他就是十进制数)后得到的结果
那么六进制中的第17个数,就是把17表示成6进制后得到的结果,即25
如果还不懂的话可以看看我以前写的博客Sichuan University Programming Contest 2018 Preliminary的D题
然后回到我们这个题,题目想问[l,r]中有多少个含有6的数字
利用前缀和的思想容易想到,就是求[0,r]中含有6的数字个数减去[0,l-1]中含有6的数字个数
那么怎么求含有6的数字个数呢?我们可以先求出有多少个不含有6的数字个数。
不含有6的数字个数怎么求呢?利用刚才那题的思想,其实就是将其理解为九进制,再将这个理解为的九进制数转换为十进制,就是其不含6的数字个数
比方说123,把它当成九进制数来理解,再转换为十进制数,即
( 123 ) 9 = 1 × 9 2 + 2 × 9 1 + 3 × 9 0 = 81 + 18 + 3 = 102 (123)_9=1 \times 9^2 + 2 \times 9^1 + 3 \times 9^0=81+18+3=102 (123)9=1×92+2×91+3×90=81+18+3=102
这说明123中不含有6的数字个数为102个,反过来说,含有6的数字个数就是123-102=21个
类似的,如果是19,把它当成九进制数来理解,转换为十进制数。这里要注意的是,我们把它当做九进制数来理解的原因是我们把符号6删去了,导致有10个符号的十进制数变成了九进制数,所以这里19中的9不再是第九个符号,而是第8个符号
( 19 ) 伪 9 进 制 = 1 × 9 + 8 = 17 (19)_{伪9进制}=1 \times 9 + 8 = 17 (19)9=1×9+8=17
也就是说19中不含6的数字个数为17个,含有6的数字个数为2
但是还有一个问题,既然我们说理解为九进制是把6删了,那么如果这个数本身就有6怎么办呢?
这时候就要做一些处理了。比方说,16432中不含有6的数字个数,其实跟15999中不含有6的数字个数是相同的,对吧,那么现在15999就是一个不含有6的数字了。同理,如果有多个6,那么我们应该取最高位的6变成5,其后各位数全部变成9,比如1654625中不含6的数字个数和1599999相同
到这里解释就差不多了,可能对于相似的方法有更容易理解的解释,但是计算方法上基本是换汤不换药的
细节比较多,所以代码也可能不那么好懂

#include<bits/stdc++.h>
using namespace std;
long long f(long long x) {
    long long p = 1, q = 1;
    long long tmp = x;
    tmp /= 10;
    while(tmp) tmp /= 10, p *= 10, q *= 9;
    long long ans = 0;
    bool flag = false;
    while(p) {
        int t = x/p; x %= p;
        if(!flag && t == 6) {
            t = 5;
            flag = true;
        }
        else {
            if(flag) t = 8;
            else if(t > 6) t--;
        }
        ans += t*q;
        p /= 10; q /= 9;
    }
    return ans;
}
long long count(long long n) {
    if(n < 6) return 0;
    return n - f(n);
}
int main() {
    long long l, r; cin>>l>>r;
    cout<<count(r) - count(l-1)<<endl;
    return 0;
}

H.处女座的百日理财计划

没做这题,留题留坑,请见官方题解
链接:https://ac.nowcoder.com/acm/contest/329/H
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述
处女座为了有更充足的资金和小姐姐一起玩耍,于是就放"高利贷"给小姐姐,一般小姐姐一周就会还钱,而处女座只要10%的利率,这样算下来,如果可以利滚利的话,1元钱经过1年(360天)可以变成51.43元呢,想起来就非常美滋滋哦!
不过总是借钱给小姐姐并不是长远之策,处女座开始了自己的百日理财计划。处女座在第一天的早上可以获得1000元的启动资金。之后在每天的早上,他会回收借给别人的到期的资金;在每天的晚上,他可以把任意整数金额的现金借给别人。对于第i个人,他要借Di天,总利息是Mi%,同时他有Pi%的概率跑路;在每天的中午,他都可以去玩一下老虎机,他可以投入整数的金额,在第i天,他有Qi%的几率让金额翻倍,同时还有1−Qi%的概率输。
现在处女座想知道,按照期望去估算每一次的投入的话,如果他采用最优策略投资,他可以反复将钱借给同一个人(大财主为啥不多奉陪呢),在第100天的晚上,他手上最多会有多少现金。
为了便于计算,处女座手上的现金只能为一个整数,每次投资多出来的小数部分会自动舍去。同时由于结果可能很大,你只需要输出对1,000,000,007取模的结果即可。

输入描述:
输入数据第一行包含一个整数N,表示愿意找处女座借钱的人数。
接下来N行,每行包括三个整数Di,Mi,Pi,含义如题目描述所示。
最后一行包括100个整数Qi,表示每一天老虎机中奖的概率。

输出描述:
一行包括一个整数,表示处女座在第100天的晚上手上最多有的钱数对1,000,000,007取模的结果。

示例1

输入
1
99 100 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 100

输出
4000

说明
处女座在第一天晚上把1000元借给第1个人,经过99天到了第100天早上收回2000元,并在当天中午玩老虎机使得自己的资金全部翻倍,最终在第100天晚上可以拥有4000元。

备注:
0 ≤ N ≤ 10 , 000 0≤N≤10,000 0N10,000
0 ≤ P i , Q i ≤ 100 0≤P_i,Q_i≤100 0Pi,Qi100
1 ≤ M i , D i ≤ 100 1≤M_i,D_i≤100 1Mi,Di100


I.处女座的约会

链接:https://ac.nowcoder.com/acm/contest/329/I
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述
处女座放完了"高利贷",拿到了不少的资金,又可以和小姐姐约会啦!(之前不还是攒钱打比赛的吗)现在处女座拿到了一份宁波市旅游地图决定和小姐姐一起去玩耍。他们来到了动物园,去参观里面的动物。但是很不幸的是,他们在游玩的途中遇到了一只恶龙。
恶龙长有n个头,但经过了处女座的调教,恶龙变得善良了一些。它的n个头每个头要么仍是邪恶的头,用“1”表示,要么已经变得善良,用“0”表示,因而恶龙的n个头就可以用n位01串来表示。而此时处女座要发挥自己的勇士形象,要把所有的龙头都变成0000⋯00完全善良的龙头。每一次,他可以砍掉龙最右侧的一个头,同时龙会在最左侧长出新的一个头,以保证龙头数量不变。如果他砍掉的是一个1,即邪恶的头,他可以决定龙在最左侧会长出什么样的头;但如果他砍掉了一个善良的头,那么玻璃心的恶龙将会在左侧不受控制的长出一个随机的头,既可能是善良的头,也可能是邪恶的头,而且它总会与处女座作对,尽力的破坏他的计划。
现在给你一个恶龙头的初始状态,即一个01串,请帮助处女座判断一下,能否在有限步之内让全部的龙头都变成善良的龙头。

输入描述:
输入第一行T,表示用例组数。
之后T行,每行一个01串S表示龙头的初始状态,“0”表示善良的头,“1”表示邪恶的头。

输出描述:
对于每组数据,处女座能否将全部的龙头变成善良的头,可以的话输出“cnznb”,不可以则输出“ljcnz”(不含引号)。

示例1

输入
1
1111

输出
cnznb

备注:
T ≤ 1000 T≤1000 T1000
∣ S ∣ ≤ 100 |S|≤100 S100

注意,这个问题可能没有你想的那么简单。显然,处女座必须把一些1变成0,这样才能让1的数量减少并消失。但是如果只是简单的每次把1变成0,最终不见得能取胜。比如,如果龙头的状态是101,那么去掉最右边的1并选择在左边长出一个0,则龙头会变成010;再把010右边的0去掉后,如果左边仍长出一个1,则龙头又变回了101的状态,如此反复,将永远不能得到000


emmmmmm这个题讲道理我不会,但是这种题吧,这么说出来,就基本上可以确定是恒真or恒假or除极少数特殊情况外恒真or除极少数特殊情况外恒假
然后就交了一发恒真
然后就AC了
嗯官方题解给出的证明挺好的,我这里直接copy过来好了!

显然处女座十分牛逼,因此输出“cnznb”即可
咳咳……至于正确的做法。首先因为每次在右边砍掉一个头就相当于在左边会多出来一个头,所以可以把每?次操作看作一轮,每轮的操作都是从01串右边向左边对每个位置在原位依次进行操作。我们考虑这种做法,从右到左我们首先看到1就把他变成0,0的话让他随机,直到第一次出现有0变成了1的情况。如果没有出现这种情况那么这个串已经符合了要求,如果有0变成1发生,那么在这之后的1我们都继续变成1。这样一轮结束之后,这个01串所表示的二进制数的的大小一定是严格增加了的(因为虽然你可能把一些1变成了0但是有一个高位的0变成了1)而这个二进制数的大小是有限的,因此在有限步内一定可以把这串数变成全0串。
时间复杂度:?(1)

#include<bits/stdc++.h>
using namespace std;
const int maxn = 105;
char s[maxn];
int main() {
    int T; scanf("%d", &T);
    while(T--) {
        scanf("%s", s);
        printf("cnznb\n");
    }
    return 0;
}

J. 处女座的比赛

没做这题,留题留坑,请见官方题解
链接:https://ac.nowcoder.com/acm/contest/329/J
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
Special Judge, 64bit IO Format: %lld

题目描述
经过了训练、资金等多方面的准备,处女座终于可以去比赛了!比赛采用codeforces赛制,也就意味着可以插人。现在有一道字符串的题目,处女座在room里看到一个用hash做的,于是决定把它hack掉。这个人的核心代码如下:

const int mod=9983;
mul[0]=p;mul[1]=q;mul[2]=r;
for (int i=0;i<26;i++)in_dex[i]=i*t+t;

int get_hash(char* s)//下标从1开始
{
    int ans=0,len=strlen(s+1);
    for (int i=1;i<=len;i++)
    ans=(ans*mul[i%3] + in_dex[s[i]-'a'])%mod;
    return ans;
}

现在处女座给你他想用来hack的第一个字符串s1,和常数p,q,r,t,请你帮他找出第二个字符串s2,使得get_hash(s1)=get_hash(s2)。

输入描述:
输入数据共两行,第一行为四个整数p,q,r,t,表示代码里的常数。
第二行为一个整数T,表示数据组数。
接下来一行,每行一个仅由小写字母构成的字符串s1,表示处女座想用来hack的字符串。

输出描述:
输出一行一个和s1不同的仅由小写字母构成的字符串s2,使得get_hash(s1)=get_hash(s2)且|s2|≤20,000。

示例1

输入
123 456 789 101
3
afyo
cycw
cogw

输出
cnztql
cnzak
cnzac

备注:
100 ≤ p , q , r ≤ 999 100≤p,q,r≤999 100p,q,r999
2 ≤ t ≤ 999 2≤t≤999 2t999 t t t是素数
1 ≤ ∣ s 1 ∣ ≤ 10 , 000 1≤|s1|≤10,000 1s110,000
1 ≤ T ≤ 1 , 000 1≤T≤1,000 1T1,000
数据保证p,q,r,t和s1均为随机生成

这套题不知不觉得就结束了,祝各位大佬们看到能愉快的AK本场比赛,同时也祝处女座早日能找到真正能够两心欢悦的小姐姐,前途似锦。

注:本次比赛中出现的所有图均为真实聊天截图,均为处女座本人所述,无任何PS部分。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值