牛客国庆集训派对Day_4~6

Day_4

A.深度学习

题目描述

小 A 最近在研究深度学习,他自己搭建了一个很牛逼的神经网络,现在他手头一共有 n 组训练数据,一开始他会给自己的神经网络设置一个 batch size,假设为 B (1≤ B≤ n) ,每次训练他都会从手头的 n 组训练数据中抽取不同的 B 组数据,然后扔到神经网络去训练。
然而小 A 的服务器并不是特别支持并行,所以运行时间和 B 成正比,每一次训练都会花费 B 秒的时间。
现在小 A 发现这样每次随机选数据的话,从概率上讲要训练好多次才能使得每组训练数据都被选中过。小 A 是一个炼丹的新手,他觉得只要所有训练数据都被选中过,那么这个模型就会很牛逼,所以只要某次训练后,如果所有训练数据都被选中过,那么他就会停止进行训练。
现在他想合理地设置 B ,使得训练总时间的期望值尽可能地短,你只需要求出这个最小的期望值。

输入描述:

第一行一个正整数 n

输出描述:

输出一个实数,表示最小的期望值,本题有spj,只要和标准答案的标准误差在 10-3 以内就算正确

示例1

输入

1

输出

1.000000

备注:

1≤ n ≤ 40
解题思路:要使得期望值最小,那么B应该设置成n并且一次训练后所有训练数据都被选中,即最小的期望值为n。
AC代码:
1 #include<bits/stdc++.h>
2 using namespace std;
3 double n;
4 int main(){
5     while(cin>>n){
6         cout<<setiosflags(ios::fixed)<<setprecision(3)<<n<<endl;
7     }
8     return 0;
9 }

D.最小生成树

题目描述

小 A 有一张 n 个点的带权无向图,这张无向图非常特别,首先第 i 个点有一个点权 ai,之后这张无向图是一张完全图,且边 (u,v) 的权值为 au+av
现在小 A 想找一个这张图的边权之和最小的生成树,需要你来帮帮他

输入描述:

第一行一个正整数 n
第二行 n 个整数 a1,a2 … an

输出描述:

输出边权和最小的生成树的边权之和
示例1

输入

3
1 2 3

输出

7

备注:

1≤ n≤ 10^5
0≤ a_i ≤ 10^9
解题思路:找带权值最小的点分别和其他n-1个点进行连线,即可组成最小生成树。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const int maxn=1e5+5;LL n,sum,a[maxn];
 5 int main(){
 6     while(cin>>n){
 7         sum=0;
 8         for(LL i=0;i<n;++i)cin>>a[i],sum+=a[i];
 9         sort(a,a+n);sum-=a[0];sum+=a[0]*(n-1);
10         cout<<sum<<endl;
11     }
12     return 0;
13 }

G.区间权值

题目描述

小 Bo 有 n 个正整数 a1..an,以及一个权值序列 w1…wn,现在他定义$ f (l, r) = ( \sum_{i=l}^r a_i ) × w_{r - l + 1} $ 
现在他想知道$ \sum_{l = 1}^n \sum_{r = l}^n f(l, r) $ 的值,需要你来帮帮他
你只需要输出答案对 109+7 取模后的值

输入描述:

第一行一个正整数 n
第二行 n 个正整数 a1..an
第三行 n 个正整数 w1..wn

输出描述:

输出答案对 10^9+7 取模后的值
示例1

输入

3
1 1 1
1 1 1

输出

10

备注:

1≤ n≤ 3e5
1≤ a_i ≤ 10^7
1≤ w_i ≤ 10^7
解题思路:手推构造两个前缀和数组,即可得到答案。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const LL mod=1e9+7;
 5 const int maxn=3e5+5;int n;
 6 LL ans,a[maxn],w[maxn],sum[maxn],tot[maxn];
 7 int main(){
 8     while(cin>>n){
 9         sum[0]=tot[0]=ans=0;
10         for(int i=1;i<=n;++i)cin>>a[i],sum[i]=sum[i-1]+a[i],tot[i]=(tot[i-1]+sum[i])%mod;
11         for(int i=1;i<=n;++i)cin>>w[i];
12         for(int i=1;i<=n;++i)
13             ans=(ans+(tot[n]-tot[n-i]-tot[i-1])*w[i]%mod+mod)%mod;
14         cout<<ans<<endl;
15     }
16     return 0;
17 }

 I.连通块计数

题目描述

小 A 有一棵长的很奇怪的树,他由 n 条链和 1 个点作为根构成,第 i 条链有 ai 个点,每一条链的一端都与根结点相连。
现在小 A 想知道,这棵长得奇怪的树有多少非空的连通子树,你只需要输出答案对 998244353 取模的值即可

输入描述:

第一行一个正整数 n
第二行 n 个正整数 a1 … an

输出描述:

输出答案对 998244353 取模后的值
示例1

输入

2
1 1

输出

6

备注:

1≤ n≤ 10^5
1≤ a_i ≤ 10^7
解题思路:
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const LL mod=998244353;
 5 LL n,ans,res,tp;
 6 int main(){
 7     while(cin>>n){
 8         ans=0;res=1;
 9         while(n--){
10             cin>>tp;
11             res=(res*(tp+1))%mod;
12             ans=(ans+tp*(tp+1)/2)%mod;
13         }
14         cout<<(ans+res)%mod<<endl;
15     }
16     return 0;
17 }

J.寻找复读机

题目描述

某个 QQ 群里一共有 n 个人,他们的编号是 1..n,其中有一些人本质上是复读机。
小 A 发现,如果一个人的本质是复读机,那么他每次发的消息一定跟群里的上一条消息一样,特别地第一个发消息的人一定不是复读机。
现在小 A 搞到了一份聊天记录,他想请你找出所有可能是复读机的群友

输入描述:

第一行两个正整数 n,m,表示群里的人数和聊天记录的总条数
接下来 m 行按时间顺序给出聊天记录,每行有一个正整数 x 和一个小写字母字符串 S,表示群友 x 发了消息 S

输出描述:

输出一行,将所有可能是复读机的群友的编号按照从小到大排序后输出,每两个编号之间隔一个空格
示例1

输入

3 5
1 gugugu
2 gugugu
1 gugu
3 tingzhifudu
2 tingzhifudu

输出

2

备注:

1≤ n≤ 10^3
1≤ m≤ 10^3
1≤ |S|≤ 100
解题思路:因为是不容易找哪个是复读机(可能没发言的也是复读机),所以我们找不是复读机的群友--->不和群里上一条消息一样的人一定不是复读机,因此标记一下这些人,最后再按顺序输出是复读机的编号即可。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,x,y,st,cnt,ans[1005];string str,tmp;bool flag[1005];
 4 int main(){
 5     while(cin>>n>>m){
 6         cin>>x>>str;st=x,cnt=0;memset(flag,false,sizeof(flag));flag[x]=true;
 7         while(--m){
 8             cin>>y>>tmp;
 9             if(tmp!=str)flag[y]=true;
10             x=y,str=tmp;
11         }
12         for(int i=1;i<=n;++i)
13             if(!flag[i])ans[cnt++]=i;
14         for(int i=0;i<cnt;++i)
15             cout<<ans[i]<<(i==cnt-1?'\n':' ');
16     }
17     return 0;
18 }

 Day_5

G.贵族用户

题目描述

终于活成了自己讨厌的样子。
充钱能让你变得更强。
在暖婊这个游戏里面,如果你充了x元钱,那么你能获得10x个钻石。同时暖婊也有m档VIP,如果你往暖婊里面充了ai个钻石,那么你能成为第i档贵族用户。当你成为第i档贵族用户之后,那么你可以获得$ p_i $%的优惠。
你需要k件材料合成衣服,其中第i件材料原价为di个钻石,你一共需要ci件这种材料。当你获得p的优惠时,这个材料的真实价格为
请问栗子米最少需要氪多少钱,这里我们规定只能氪整数的钱。

输入描述:

第一行一个整数T(T≤ 1000),表示数据组数。
每组数据第一行两个整数m,k(1≤ m,k≤ 15)。
接下来m行每行两个正整数1≤ a_i ≤ 10^5, 1≤ p_i ≤ 100,保证a_i ≤ a_(i+1),p_i ≤ p_(i+1).
接下来k行每行两个正整数1≤ ci, di≤ 1000。

输出描述:

对于每组数据,输出一个整数,表示至少要氪多少钱。
示例1

输入

1
1 1
100 100
100 100

输出

10
解题思路:遗忘补缺---精度处理!
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int input(){
 4     int x=0,f=1;char ch=getchar();
 5     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 6     while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
 7     return f*x;
 8 }
 9 struct node1{int a,p;}nod1[15];
10 struct node2{int c,d;}nod2[15];
11 int T,m,k,ans,tmp;
12 int _ceil(int x){return x%100==0?x/100:x/100+1;}
13 void solve(){
14     ans=0;m=input();k=input();
15     for(int i=0;i<m;++i)nod1[i].a=input(),nod1[i].p=input();
16     for(int i=0;i<k;++i)nod2[i].c=input(),nod2[i].d=input(),ans+=nod2[i].c*nod2[i].d;
17     for(int i=0;i<m;++i){
18         tmp=0;
19         for(int j=0;j<k;++j)
20             tmp+=_ceil(nod2[j].d*(100-nod1[i].p))*nod2[j].c;
21         ans=min(ans,max(tmp,nod1[i].a));
22     }
23     printf("%d\n",ans%10==0?ans/10:ans/10+1);
24 }
25 int main(){
26     T=input();
27     for(int i=1;i<=T;i++)solve();
28     return 0;
29 }

L.数论之神

题目描述

终于活成了自己讨厌的样子。

这是她们都还没长大的时候发生的故事。那个时候,栗子米也不需要为了所谓的爱情苦恼。
她们可以在夏日的午后,花大把的时间去研究生活中一些琐碎而有趣的事情,比如数论。
有一天西柚柚问了栗子米一个题,她想知道中有多少不同的数,这些不同的数字里面第k大的是多少。

输入描述:

第一行一个整数T(T≤ 10^5 ),表示数据组数。
每组数据第一行两个整数,表示n,k(1≤ n≤ 10^18),保证k不会超过不同的数字个数。

输出描述:

对于每组数据输出,输出两个整数,表示有多少个不同的数字和这里面第k大的是多少。
示例1

输入

3
1 1
5 2
67 8

输出

1 1
3 2
15 8
解题思路:找规律发现一定是1,2,3,...,x,n/(x-1),n/(x-2),...,x是sqrt(n)附近,求出第k大即可。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 int t;LL n,k,x,y,tot,tp;
 5 int main(){
 6     while(cin>>t){
 7         while(t--){
 8             cin>>n>>k;
 9             x=sqrt(n);
10             if(n/x!=x)tp=0;
11             else tp=-1;//多了一个重复的元素,增量为-1
12             tot=2*x+tp;
13             k=tot-k+1;//第k大的位置
14             if(k<=x)y=k;//y直接赋值为k
15             else y=n/(tot-k+1);// n/(x-m)
16             cout<<tot<<' '<<y<<endl;
17         }
18     }
19     return 0;
20 }

 Day_6

B.board

题目描述

恬恬有一个nx n的数组。她在用这个数组玩游戏:
开始时,数组中每一个元素都是0。
恬恬会做某些操作。在一次操作中,她可以将某一行的所有元素同时加上一个值,也可以将某一列的所有元素同时加上一个值。
在几次操作后,一个元素被隐藏了。你能帮助她回忆隐藏的数是几吗?

输入描述:

第一行一个整数n(1≤ n≤ 1000)。
接下来n行每行n个整数表示数组a。
第(i+1)行的第j个元素表示a_i_j(a_i_j=-1或 0 ≤ a_i_j ≤ 10000)。-1表示隐藏的元素。

输出描述:

仅一个整数表示答案。
示例1

输入

3
1 2 1
0 -1 0
0 1 0

输出

1
解题思路:由于数据较小,记录-1这个元素的坐标,并将其赋值为1w,然后暴力模拟减一下,最后肯定只剩下这个元素(其余全为0),其值记为m',即被隐藏的值为1w-m'。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 int n,ex,ey,cnt,minv,mp[1005][1005];
 5 int main(){
 6     while(~scanf("%d",&n)){
 7         memset(mp,0,sizeof(mp));
 8         for(int i=0;i<n;++i){
 9             for(int j=0;j<n;++j){
10                 scanf("%d",&mp[i][j]);
11                 if(mp[i][j]==-1)ex=i,ey=j,mp[i][j]=10000;
12             }
13         }
14         for(int i=0;i<n;++i){
15             cnt=0;minv=20000;
16             for(int j=0;j<n;++j)
17                 if(mp[i][j]>0)cnt++,minv=min(minv,mp[i][j]);
18             if(cnt==n&&minv!=20000){
19                 for(int j=0;j<n;++j)
20                     mp[i][j]-=minv;
21             }
22         }
23         for(int j=0;j<n;++j){
24             cnt=0;minv=20000;
25             for(int i=0;i<n;++i)
26                 if(mp[i][j]>0)cnt++,minv=min(minv,mp[i][j]);
27             if(cnt==n&&minv!=20000){
28                 for(int i=0;i<n;++i)
29                     mp[i][j]-=minv;
30             }
31         }
32         printf("%d\n",10000-mp[ex][ey]);
33     }
34     return 0;
35 }

C.Circle

题目描述

现在我们要把1...n这n个数字首尾连接组成一个环,使得相邻元素互质的对数尽可能多。请输出最大对数。

输入描述:

一行一个整数n(1≤ n≤ 1000)。

输出描述:

一行一个整数表示答案。
示例1

输入

4

输出

4

说明

样例的一种构造方法为1 4 3 2。
解题思路:把1放首位置,由于相邻的奇数和偶数肯定互质,所以把1...n这n个元素依次放入一个环就可以,即最大对数为n。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 int n;
 5 int main(){
 6     while(cin>>n){
 7         cout<<n<<endl;
 8     }
 9     return 0;
10 }

H.Mountain

题目描述

平面上有n座山,每座山都有左右两面,第i座山的高度为ai,现在弱弱在第一座山的左边山脚下(高度为0),他想要依此爬过这些山,到达第n座山的右边山脚下。
除了简单的爬上爬下,还有一种特殊操作。
如果弱弱目前在第i座山右面的海拔x的位置,且第j ( i < j )座山的海拔大于等于x,且第i + 1,...,j - 1座山中没有一座山的海拔高于x,那么他可以使用绳索滑到第j座山左面海拔x的位置。
弱弱想找到一种方式,使得他在行程中海拔变化的幅度最小。请输出最小幅度。

输入描述:

第一行一个整数n(1≤ n ≤ 1000)。
接下来一行n个整数a_i(1 ≤ a_i ≤ 1000)表示每座山的高度。

输出描述:

一行一个整数表示答案。
示例1

输入

5
1 3 5 4 2

输出

10
解题思路:最小幅度一定是最高山的高度的两倍。
AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 int n,ans,m;
 5 int main(){
 6     while(cin>>n){
 7         ans=0;
 8         for(int i=0;i<n;++i)cin>>m,ans=max(ans,m);
 9         cout<<ans*2<<endl;
10     }
11     return 0;
12 }

 

posted @ 2018-10-04 18:34  霜雪千年  阅读(494)  评论(0编辑  收藏  举报