牛客网平台常州大学新生寒假训练会试
A-添加逗号
链接:https://www.nowcoder.net/acm/contest/78/A
来源:牛客网
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
输入描述:
一行一个整数 N
输出描述:
一行一个字符串表示添加完逗号的结果
输入
980364535
输出
980,364,535
备注:
1≤n≤2,000,000,000
考察内容:数字拆分,字符串处理,细节处理。
#include <bits/stdc++.h> using namespace std; int main(){ int n, i, x[100005], j, m, y, q; scanf("%d",&n); i = 0; m = 0; while(n > 0){ x[i] = n % 10; n = n/10; i++; } y = i; while(i > 3){ i = i - 3; m++; } for(j = y - 1;j >= y - i;--j){ cout << x[j]; } for(j = 0;j < m;++j){ cout << ","; for(q = 0;q < 3;++q){ cout << x[y - i - 1]; i++; } } cout << endl; return 0; }
B-对称
链接:https://www.nowcoder.net/acm/contest/78/B
来源:牛客网
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
输入描述:
一行两个整数 N,M
输出描述:
一行一个整数,即需要的棋子数
输入
7 15
输出
21
输入
3 1
输出
1
说明
不一定变成4个部分,存在中心位置即可
备注:
1≤n,m≤1,000,000,000。
题解:找规律,很容易发现只有 m,n 为奇数时才能找到中心,然后模拟统计即可。
#include<cstdio> #include<cstdlib> #include<iostream> #include<cstring> #include<algorithm> using namespace std; long long chen(int n) { int i; long long s=1; for (i=1;i<=n;++i) s*=4; return s; } int main() { int n,m,i=0; long long s=0; scanf("%d %d",&n,&m); while (n>1 || m>1){ if (n%2==0||m%2==0) break; s+=chen(i); n/=2; m/=2; i++; } if (m==1&&n==1)s+=chen(i); cout<<s<<endl; return 0; }
C-竞赛技巧
链接:https://www.nowcoder.net/acm/contest/78/C
来源:牛客网
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
输入描述:
第 1 行,一个整数 N 第 2~n+1 行,每行 3 个整数,表示时,分,秒
输出描述:
共 n 行,每行 3 个整数,表示排序完后的结果
输入
3 11 20 20 11 15 12 14 20 14
输出
11 15 12 11 20 20 14 20 14
说明
所以在保证能做对的情况下,我们应当尽量减少罚时
考察内容:排序
#include<iostream> #include<algorithm> #include<cstdio> using namespace std; int n; struct Time { int h,m,s; } t[5000]; bool comp (Time t1, Time t2) { return t1.h < t2.h || (t1.h == t2.h && t1.m<t2.m) || (t1.h == t2.h && t1.m == t2.m && t1.s<t2.s); } int main () { cin >> n; for (int i = 0; i < n; i++) cin >> t[i].h >> t[i].m >> t[i].s; for (int i = 0; i < n-1; i++) { int min = i; for (int j = i+1; j < n; j++) if (comp(t[j],t[min])) min = j; Time tmp = t[i]; t[i] = t[min],t[min] = tmp; } for (int i = 0; i < n; i++) cout << t[i].h << " " << t[i].m <<" " << t[i].s << "\n"; return 0; }
#include<bits/stdc++.h> using namespace std; struct sam { int x,y,z; }; int cmp(sam &p,sam &q) { return (p.x<q.x||(p.x==q.x&&p.y<q.y)||(p.x==q.x&&p.y==q.y&&p.z<q.z)); } int main() { int n,i; sam a[10000]; scanf("%d",&n); for (i=1;i<=n;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); sort(a+1,a+1+n,cmp); for (i=1;i<=n;i++) printf("%d %d %d\n",a[i].x,a[i].y,a[i].z); }
D-训练技巧
链接:https://www.nowcoder.net/acm/contest/78/D
来源:牛客网
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
输入描述:
第一行:两个用空格隔开的整数:N和K,1≤N≤100000,1≤K≤N
第二行到N+1行:第i+1行有一个整数,表示第N天的训练效果是Ei,(0 <= Ei <= 1,000,000,000)
输出描述:
第一行:单个整数,表示最大的能力之和
输入
5 2 1 2 3 4 5
输出
12
说明
(除了第三天以外每天都在训练,总训练效果为1+2+4+5=12)
备注:
1≤n≤100,000
考察内容:动态规划,单调队列。
题解:这题应该是个经典的动态规划问题(原题),用单调队列优化。
用 dp[i]表示不取 i,且取法合法的最小损失,那么 dp[i]=min{dp[j]+a[i]},其中 i-j<=k。
注意到可以用单调队列优化。我们用 q[i]表示目前符合条件的位置,直接更新即可。
开 long long,ans 初始值要足够大。复杂度 O(nlogn)
#include<cstdio> #include<cstring> #include<iostream> using namespace std; #define ll long long int n,k,st,ed,q[100001]; ll dp[100001],a[100001],ans,tot; ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();} while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return x*f; } int main() { n=read();k=read();ans=99999999999999999ll; for(int i=1;i<=n;i++) a[i]=read(),tot+=a[i]; for(int i=1;i<=n;i++) { dp[i]=a[i]+dp[q[st]]; while(st<=ed && dp[q[ed]]>dp[i]) ed--;q[++ed]=i; while(q[st]<i-k) st++; } for(int i=n-k;i<=n;i++) ans=min(ans,dp[i]); printf("%lld\n",tot-ans); return 0; }
E-这是一个数学题
链接:https://www.nowcoder.net/acm/contest/78/E
来源:牛客网
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
输入描述:
第一行输入四个数 n,A0
,An,Q
输出描述:
对于每组查询输出A到Ar的和
输入
3 0 3 2 1 1 1 3
输出
1 6
备注:
为了对萌新表现出友好,数据保证了对于Ai的每一项都是整数
考察内容:简单数学公式。
题解:考虑将两边组合数化简于是得到
熟悉的同学应该能一眼发现 Ai 是个等差数列,公差
接下来查询就是一个等差数列求和,运用等差数列求和公式即可复杂度 O(1)
由于这题没有设置取模,所以在乘的时候要小心爆。
事实上这个结论可以加强为Ai 是等差数列的充要条件是:
#include<bits/stdc++.h> #define cl(a,b) memset(a,b,sizeof(a)) #define debug(a) cerr<<#a<<"=="<<a<<endl using namespace std; typedef long long ll; typedef pair<int,int> pii; const int maxn=1e5+10; int n,a0,an,q,p; void query(int l,int r) { ll al=a0+1ll*p*l; ll ar=a0+1ll*p*r; ll sum=(al+ar)*(r-l+1)/2; printf("%lld\n",sum); } int main() { while(~scanf("%d%d%d%d",&n,&a0,&an,&q)) { p=(an-a0)/n; int l,r; while(q--) { scanf("%d%d",&l,&r); query(l,r); } } return 0; }
F-大佬的生日礼包
链接:https://www.nowcoder.net/acm/contest/78/F
来源:牛客网
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
豪华礼包:一个U盘、一个鼠标和一个机械键盘。
幸运礼包:一个U盘、两个鼠标。
普通礼包:两个U盘、一个鼠标。
输入描述:
输入第一行包含一个正整数T。
接下来T行每行包含3个正整数a, b, c,依次表示U盘、鼠标和机械键盘各有多少个。
输出描述:
输出T行,每行一个整数,表示最多能发出多少份礼包。
输入
2 4 4 0 1 1 1
输出
2 1
备注:
T<=100000
0<=a,b,c<=1000000
考察内容:贪心,分类讨论,二分。
题解:首先观察题目可知,一共 1e5 个查询,这需要我们在 O(1)或者 O(logn)级别计算出结果。
- 解法一:由于礼包只有三种,显然答案和 a,b,c 存在这公式的关系,所以分类讨论几种情况即可。
- 解法二:我们发现只有豪华礼包才有键盘,而豪华礼包只需要 1 个 U 盘和 1 个鼠标。所以我们可以通过二分答案或者二分豪华礼包的方法来得到答案。
#include<bits/stdc++.h> using namespace std; int main() { int T,a,b,c,s,t,ans,x,y,a1,b1,c1,ans1; scanf("%d",&T); while (T--) { scanf("%d%d%d",&a,&b,&c); if (a<c) c=a; if (b<c) c=b; if (a<b) { t=a; a=b; b=t; } a1=a;b1=b;c1=c; t=a-b; ans1=0;ans=0; if (c<=t) { x=(c-1)*2+c; y=c-1+c; if (x<=a&&y<=b) { ans=c+c-1; a-=x;b-=y; x=min(a/3,b/3); ans+=x*2; a-=x*3;b-=x*3; if (a>=2&&b>=1) ans++; } else { x=min(a/3,b/2); a-=x*3;b-=x*2; ans=x*2; if (a>=1&&b>=1) ans++; } } else { x=t*2+t; y=t+t; if (x<=a&&y<=b) { ans=t+t; a-=x;b-=y; c-=t; x=min(a/5,b/5); x=min(x,c/2); ans+=x*4; a-=x*5;b-=x*5;c-=x*2; if (a>=1&&b>=1&&c>=1) { a--;b--;c--; ans++; } x=min(a/3,b/3); ans+=x; a-=x*3;b-=x*3; if (a>=2&&b>=1) ans++; } else { x=min(a/3,b/2); a-=x*3;b-=x*2; ans=x*2; if (a>=1&&b>=1) ans++; } } ans1=ans;ans=0; a=a1;b=b1;c=c1;t=a-b; if (t>=c) { x=c*2+c; y=c+c; if (x<=a&&y<=b) { ans=c+c; a-=x;b-=y; x=min(a/3,b/3); ans+=x*2; a-=x*3;b-=x*3; if (a>=2&&b>=1) ans++; } else { x=min(a/3,b/2); a-=x*3;b-=x*2; ans=x*2; if (a>=2&&b>=1) ans++; } } else { x=t*2+t; y=t+t; if (x<=a&&y<=b) { ans=t+t; a-=x;b-=y; c-=t; x=min(a/5,b/5); x=min(x,c/2); ans+=x*4; a-=x*5;b-=x*5;c-=x*2; if (a>=3&&b>=2&&c>=1) { a-=3;b-=2;c--; ans+=2; } x=min(a/3,b/3); ans+=x*2; a-=x*3;b-=x*3; if (a>=1&&b>=2) ans++; } else { x=min(a/3,b/2); a-=x*3;b-=x*2; ans=x*2; if (a>=2&&b>=1) ans++; } } ans=max(ans,ans1); a=a1;b=b1;c=c1; if (c==0) { x=min(a/3,b/3); ans=x*2; a-=x*3;b-=x*3; if (a>=2&&b>=1) ans++; } printf("%d\n",ans); } }
#include<bits/stdc++.h> using namespace std; #define LL long long #define LD long double #define For(i,j,k) for (int i=j;i<=k;++i) #define foR(i,j,k) for (int i=j;i>=k;--i) #define mem(a,x) memset(a,x,sizeof(a)) #define sqr(x) (x)*(x) template <typename T>void cmin(T &a,T b){a=min(a,b);} template <typename T>void cmax(T &a,T b){a=max(a,b);} template <typename T> void read(T &x){ char c;T f=1; while (!isdigit(c=getchar())) if (c=='-') f=-1; x=c-'0'; while (isdigit(c=getchar())) x=x*10+c-'0'; x*=f; } int main(){ freopen("store.in","r",stdin); freopen("store.out","w",stdout); int T; read(T); For (i,1,T){ int a,b,c;read(a),read(b),read(c); int l=0,r=0x7fffffff; while (l+1<r){ int mid=(l+r)>>1,A=a-mid,B=b-mid,C=c; if (A>=0&&B>=0&&A+B+C>=mid&&(A+B)>=mid>>1&&(B+C)>=mid>>1&&(A+C)>=mid>>1) l=mid; else r=mid; } printf("%d\n",l); } return 0; }
G-零下e度
链接:https://www.nowcoder.net/acm/contest/78/G
来源:牛客网
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
输入描述:
一行一个整数n
1<=n<=10^8
输出描述:
一行一个整数,即题目描述中所求,由于这个数字可能很大,我们只需要知道mod 998244353后的结果(出题人负责任地告诉你,这个数字是个质数)
输入
6
输出
265
输入
87
输出
158005593
输入
16777216
输出
16065816
考察内容:组合数学 递推。
题解:我们将 n!/e 分成两部分 n!的意义是 n 个数的全排列,由于 1/e = e^(-1) = 1/0! - 1/1! + 1/2! - ..... + (-1)^n/n! + Rn(-1),其中 Rn(-1)是余项,等于(-1)^(n+1) * e^u / (n+1)!,且 u∈(-1, 0)。
相乘就是一个错排公式 D(n) = n! (1/0! - 1/1! + 1/2! - 1/3! - ..... +(-1)^n/n!),所以,D(n) = n! * e^(-1) - (-1)^(n+1) * e^u / (n+1), u∈(-1, 0).。而|n! Rn| = |(-1)^(n+1) * e^u / (n+1)| = e^u / (n+1) ∈ (1/[e(n+1)],1/(n+1)),可知即使在 n=1 时,该余项(的绝对值)也小于 1/2。
因此,无论 n! Rn 是正是负,n! / e + 1/2 的整数部分都一定与 M(n)相同。所以这题就变成了求 n 位数的错排。
对于 n<=1e8 的单组查询,我们有递推式D(n) = (n-1) [D(n-2) + D(n-1)]
显然不能用数组存,维护三个变量更新即可。
注意取模的常数较大尽量减少取模。
#include<bits/stdc++.h> using namespace std; int main() { int n,i,j,k,f; long long x,y,q=998244353,ans,s; scanf("%d",&n); if (n==1) ans=0; if (n==2) ans=1; x=0; y=1; for (i=3;i<=n;i++) { s=(x+y)*(i-1)%q; x=y; y=s; } if (n>2) ans=y; cout<<ans<<endl; }
相关链接:错排公式
H-酸碱滴定
链接:https://www.nowcoder.net/acm/contest/78/H
来源:牛客网
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
输入描述:
输入第一行一个数T(T<=20)表示数据组数
对于每组数据输入 A,B,C三个3位小数
0.000<a,b,c<50.000
输出描述:
结果“四舍六入五成双”保留2位小数
输入
3 10.000 10.000 1.825 10.000 10.000 9.835 1.010 21.325 19.823
输出
1.82 9.84 0.94
说明
样例1中计算出的结果为 1.8250000000根据(规则3.2.2) 答案应该为1.82
9.835->9.84(规则3.2.1)
考察内容:细节处理。
题解:答案就是 a*c/b,然后根据规则分类讨论下就好,注意进位。
#include <bits/stdc++.h> using namespace std; void solve(){ double a, b, c; cin >> a >> b >> c; double ans = (a * c )* 100.0 / b; if( ans-(int)ans < 0.499 ) ans = (int)ans / 100.0; else if ( ans-(int)ans >0.501 ) ans = ((int)ans+1) / 100.0; else{ if( ((int)ans)%2 ) ans = ((int)ans+1) / 100.0; else ans = (int)ans / 100.0; } printf("%.2lf\n", ans); return; } int main(){ int n; cin >> n; while(n--){ solve(); } return 0; }
I-合成反应
链接:https://www.nowcoder.net/acm/contest/78/I
来源:牛客网
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
输入描述:
第一行输入四个整数 K,N,M,Q(K,N,M,Q<=1e5)
K表示一共K总物质
接下来N行 每行三个数字a b c(任意两个数可能相等)
表示a和b反应可以生成c 反应是可逆的
即可以通过c可以分解出a和b
接下来一行行然后输入m个数,表示m种原料(每一种原料都可以认为有无限多)
接下来Q个行Q个询问
对于每个询问
输出一个数字 x 判断是否可以通过一些反应得到第 x
输出描述:
可以得到Yes否则No
输入
10 3 4 10 1 2 3 4 5 6 2 5 7 3 4 5 8 1 2 3 4 5 6 7 8 9 10
输出
Yes Yes Yes Yes Yes Yes Yes Yes No No
说明
一共10总物质有第3,4,5,8 四种原料
查询每一种是否可以通过反应得到
首先通过3可以分解得到1 2
然后4 5合成6
2 5合成7
于是除了9 10都可以得到
考察内容:bfs 暴力剪枝
题解:这道题灵感来源是有机化学中的合成题。
解法一:
首先的一个最简单想法是每次对所以配方做一次分解,一次合成,然后做到无法做很不幸这样的做法被出题人卡掉了,但是我们可以尝试剪枝剪过去。
每次优先考虑分解,一旦发现合成新的物质就先去分解,然后检查一下能否合成这两步无限循环,发现无法合成就跳出,这样复杂的是均摊 O(logn)级别的,出题人水平有限卡不掉。
解法二:
标程的做法是 bfs
我们考这样一个有向图对于每个配方建四条边
c->b 权值为 a ,
c->a 权值为 b
a->c 和 b->c 权值为-1
比如输入的配方是(a, b),能合成 c
然后建四条边
c->b 权值为-1
c->a 权值为-1
a->c 权值为 b
b->c 权值为 a
然后做一次 bfs 首先把原料都丢进去队列,然后每次到一个点访问它的后继 如果它和它的权值都是有的那么就丢进去。
例如节点 x 能到节点 y 的条件是他们之间的有向边的权值 z 是-1 或者 zx 存在原料库当中的 这样复杂度大概是 O(N+M)。
#include<bits/stdc++.h> using namespace std; struct sam { int x,y,z; }; int n,i,j,k,s,t,m,q,top,tail,f; sam a[100010]; int b[100010],c[200010],d[100010][3]; int cmp(sam &p,sam &q) { return (p.z<q.z); } int work(int t) { int ans; if (d[t][1]==0&&d[t][2]==0) return 0; ans=d[t][1]; while (ans<=d[t][2]) { if (b[a[ans].x]==0) { b[a[ans].x]=1; top++; c[top]=a[ans].x; } if (b[a[ans].y]==0) { b[a[ans].y]=1; top++; c[top]=a[ans].y; } ans++; } return 1; // b[t]=2; } int main() { scanf("%d%d%d%d",&k,&n,&m,&q); for (i=1;i<=n;i++) { scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); } sort(a+1,a+1+n,cmp); memset(d,0,sizeof d); for (i=1;i<=n;i++) { t=a[i].z; if (d[t][1]==0) d[t][1]=i; d[t][2]=i; } tail=1;top=0; for (i=1;i<=m;i++) { scanf("%d",&t); if (b[t]==0) { b[t]=1; top++; c[top]=t; } } while (tail<=top) { work(c[tail]); tail++; } f=0; while (f==0) { f=1; for (i=1;i<=n;i++) if (b[a[i].x]>0&&b[a[i].y]>0&&b[a[i].z]==0) { f=0; b[a[i].z]=1; top++; c[top]=a[i].z; while (tail<=top) { work(c[tail]); tail++; } } if (f==1) break; f=1; for (i=n;i>=1;i--) if (b[a[i].x]>0&&b[a[i].y]>0&&b[a[i].z]==0) { f=0; b[a[i].z]=1; top++; c[top]=a[i].z; while (tail<=top) { work(c[tail]); tail++; } } } for (i=1;i<=q;i++) { scanf("%d",&t); if (b[t]==0) printf("No\n"); else printf("Yes\n"); } }
#include<bits/stdc++.h> using namespace std; int a[100010]; struct hxfy { int x,y,z; } b[100010]; int c[100010]; struct node { int x,v; }; vector<node> v[100010]; queue<int> Q; int vis[100010]; void bfs() { while(!Q.empty()) { int f=Q.front(); // cout<<f<<endl; Q.pop(); for(int i=0; i<v[f].size(); i++) { if(v[f][i].v==-1) { if(vis[v[f][i].x]==0) { a[v[f][i].x]=1; Q.push(v[f][i].x); vis[v[f][i].x]=1; } } else { if(a[v[f][i].v]) { if(vis[v[f][i].x]==0) { Q.push(v[f][i].x); vis[v[f][i].x]=1; a[v[f][i].x]=1; } } } } } } int main() { //freopen("1","r",stdin); // freopen("2","w",stdout); int k,n,m,q; scanf("%d%d%d%d",&k,&n,&m,&q); for(int i=1; i<=n; i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); b[i].x=x; b[i].y=y; b[i].z=z; v[x].push_back((node) { z,y }); v[y].push_back((node) { z,x }); v[z].push_back((node) { y,-1 }); v[z].push_back((node) { x,-1 }); } memset(a,0,sizeof(a)); memset(c,0,sizeof(c)); memset(vis,0,sizeof(vis)); for(int i=1; i<=n; i++) { c[b[i].z]=i; } for(int i=1; i<=m; i++) { int x; scanf("%d",&x); a[x]=1; Q.push(x); } bfs(); for(int i=1; i<=q; i++) { int x; scanf("%d",&x); if(a[x]) printf("Yes\n"); else printf("No\n"); } }
J-同分异构体
链接:https://www.nowcoder.net/acm/contest/78/J
来源:牛客网
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
输入描述:
输入一个数n(n<=9)
输出描述:
一个整数表示答案
输入
3
输出
1
输入
4
输出
2
输入
5
输出
3
备注:
这里不考虑空间异构
考察内容:打表。
#include<bits/stdc++.h> using namespace std; int a[11]={1,1,1,2,3,5,9,18,35}; int main() { int n; cin>>n; cout<<a[n-1]<<endl; }
您的资助是我最大的动力!
金额随意,欢迎来赏!
本博客的所有打赏均将用于博主女朋友的化妆品购买以及养肥计划O(∩_∩)O。我是【~不会飞的章鱼~】!