A题 礼尚往来
给出n,表示1~n人送的礼物,分配给这n个人,要求不能分配给送这份礼物的人,这主要是个错排公式,解说:错排公式
(n-1)*(dp[n-1] + dp[n-2])
#include <iostream>
const int mod = 1e9 + 7 ;
using namespace std ;
typedef long long ll ;
const int N = 105 ;
ll a[N] ;
int main(){
int t ;
cin >> t ;
a[1] = 0 , a[2] = 1 ;
for (int i = 3 ; i <= N ; ++ i)
a[i] = (i-1)*(a[i-1] + a[i-2])%mod ;
while(t --){
int n ;
cin >> n ;
cout << a[n] << endl ;
}
return 0 ;
}
C 题 屌丝逆袭
题意:计算周围四个数的总和价值最大,同号相减异号相加,同时比较最大值的下标,最后输出即可。
#include <iostream>
#include <cstring>
using namespace std ;
const int N = 25 ;
int maze[N][N] ;
int f[N][N] ;
int dir[4][2] = {{1,0},{0,1},{-1,0},{0,-1}} ;
int main(){
int n , m ;
while(cin >> n >> m){
if (n == 0 && m == 0) break ;
memset(f,0,sizeof(f)) ;
for (int i = 1 ; i <= n ; ++ i)
for (int j = 1 ; j <= m ; ++ j)
cin >> maze[i][j] ;
int a = 1 , b = 1 ;
for (int i = 1 ; i <= n ; ++ i){
for (int j = 1 ; j <= m ; ++ j){
int flag ;
if (maze[i][j] < 0) flag = 1 ;
else flag = -1 ;
for (int k = 0 ; k < 4 ; ++ k){
int x = i+dir[k][0] , y = j+dir[k][1] ;
if (x>=1&&x<=n&&y>=1&&y<=m)
f[i][j] += flag*maze[x][y] ;
}
if (f[a][b] < f[i][j])
a = i , b = j ;
}
}
cout << a << " " << b << " " << f[a][b] << endl ;
}
return 0 ;
}
D题 口算训练
题意:给出n个数。和q个询问,每个询问包含l,r,d ,问在区间[l,r]中的数相乘之后的数是否是d的倍数。
题解:记录n个数中每个数的质因子出现的下标,然后d也分解质因子的下标,若个数和区间都符合就输出Yes否则输出No,详细看代码。
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std ;
const int N = 1e5 + 5 ;
vector<int> g[N] ;
bool judge(int l , int r , int d){
for (int i = 2 ; i*i <= d ; ++ i){ //这里i*i要<=x
int cnt = 0 ;
while(d % i == 0){
++ cnt ;
d /= i ;
}
if (cnt){
int t = upper_bound(g[i].begin(),g[i].end(),r)-lower_bound(g[i].begin(),g[i].end(),l);
if (t < cnt) return false ;
}
}
if (d > 1) {
int t=upper_bound(g[d].begin(),g[d].end(),r)-lower_bound(g[d].begin(),g[d].end(),l);
if(t < 1) return false ;
else return true ;
}
return true ;
}
int main(){
int t ;
scanf ("%d",&t) ;
while(t --){
int n , q ;
for (int i = 1 ; i <= N; ++ i) g[i].clear() ;
scanf ("%d%d",&n,&q) ;
for (int i = 1 ; i <= n ; ++ i){
int x ;
scanf ("%d",&x) ;
for (int j = 2 ; j*j <= x ; ++ j){ //这里j*j要<=x
while(x%j == 0){
g[j].push_back(i) ;
x /= j ;
}
}
if (x > 1) g[x].push_back(i) ;
}
while(q --){
int l , r , d ;
scanf ("%d%d%d",&l,&r,&d) ;
if (judge(l,r,d)) printf ("Yes\n") ;
else printf ("No\n") ;
}
}
return 0 ;
}
E题 子串查询
题意:给出一串长度为n的字符串,然后有q个询问,询问区间[l,r]之间最小的子串有多少个,因为a比aa还小,所以只要统计该区间最小的字符个数即可。
#include <cstdio>
#include <cstring>
using namespace std ;
const int N = 1e5 + 5 ;
int cnt[N][26] ;
char s[N] ;
int main(){
int t ;
scanf ("%d",&t) ;
for (int k = 1 ; k <= t ; ++ k){
int n , q ;
scanf ("%d%d",&n,&q) ;
scanf ("%s",s) ;
memset(cnt,0,sizeof(cnt)) ;
cnt[0][s[0]-'A'] ++ ;
for (int i = 1 ; i < n ; ++ i){
for (int j = 0 ; j < 26 ; ++ j){
cnt[i][j] = cnt[i-1][j] ;
}
++ cnt[i][s[i]-'A'] ;
}
printf ("Case #%d:\n",k) ;
while(q --){
int l , r ;
scanf ("%d%d",&l,&r) ;
int ans = 0 ;
-- l , -- r ; //因为下标是从0开始的
for (int i = 0 ; i < 26 ; ++ i ){
if (cnt[r][i] - cnt[l-1][i] != 0){
ans = cnt[r][i] - cnt[l-1][i] ; //找到最小的字符串个数
break ;
}
}
printf ("%d\n",ans) ;
}
}
return 0 ;
}
F题
找最小值,略。
H题
题意:电梯从0层开始,上一层需要6秒,下一层需要4秒,一个人出电梯门需要1秒。
将所有人要去的层数升序排列,然后每到一个新层数,就用新层数减去旧层数然后乘于6 再+1 , 若不是新层数就+1即可,最后用最高的层数乘于4(要返回0层)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std ;
const int N = 20 ;
int a[N] ;
int main(){
int t ;
cin >> t ;
while(t --){
int n ;
cin >> n ;
memset(a,0,sizeof(a)) ;
for (int i = 1 ; i <= n ; ++ i){
cin >> a[i] ;
}
sort(a+1,a+n+1) ;
int sum = 6*a[1] + 6 ;
for (int i = 2 ; i <= n ; ++ i){
if (a[i] != a[i-1]){
sum += 6*(a[i]-a[i-1]) + 6 ;
}
else ++ sum ;
}
sum += a[n]*4 ;
cout << sum << endl ;
}
return 0 ;
}