个人题解(做完题赶快写题解,趁热打铁,希望对你有帮助)
题目描述:找到任意一组满足题目中描述的条件的数组就好了
思路:n,1,n-1,2,n-2,3.... 这样就是一组解
#include <iostream>
using namespace std;
const int N = 110;
int t,n,m;
char g[N][N];
int main()
{
int n;
cin >> n;
int l = 1,r = n;
while(l < r)
{
cout << r << ' ' << l << ' ';
r --;
l ++;
}
if(n % 2 != 0)
cout << l << endl;
return 0;
}
题目描述:求 
思路:先算出该怎么计算就怎么算,比如
,就先算出
,然后再算出
,那么答案不就是
吗,因为这个地方算出的结果可能很大,所以要在算的过程中不断地取模,而且这个让取模的数是个大素数,所以可以通过乘法逆元来求出最终答案,
,这个可以通过快速幂迅速求出来
#include <iostream>
#include <set>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
LL n,k;
set<LL>st;
LL qmi(LL a,LL b)
{
LL res = 1;
while(b){
if(b & 1) res = res * a % mod;
a = a * a % mod;
b = b >> 1;
}
return res;
}
int main()
{
cin >> n >> k;
for(int i = 0;i < n;i ++)
{
LL x;
cin >> x;
st.insert(x);
}
LL m = st.size();
LL s1 = 1,s2 = 1;
for(int i = m;i > m - k;i --)
{
s1 = s1 * i % mod;
}
for(int i = 1;i <= k;i ++)
{
s2 = s2 * i % mod;
}
LL s3 = s1 * qmi(s2,mod - 2) % mod;
cout << s3 << endl;
return 0;
}
题目描述:简简单单的思维题
思路:输出A的情况就是1,2或者2,1
#include <iostream>
using namespace std;
const int N = 110;
int t,n,m;
char g[N][N];
int main()
{
int a,b;
cin >> a >> b;
if(a == 1 && b == 2 || a == 2 && b == 1){
cout << 'A' << endl;
}else{
cout << 'B' << endl;
}
return 0;
}
题目描述:如果能在有限次操作将字符串变成匹配的,请输出最少的操作次数。否则输出-1
思路:先把那些不能匹配的括号找出来,找出来的括号肯定是类似于这个样子的))))((((,如果这样的括号数量为奇数,那么肯定不能通过一定的操作次数让他们都找到自己的匹配方,所以此时 l + r肯定是偶数,如果l是偶数 那么答案就是 l + r >> 1,比如)))),l = 4,r = 0,操作两次就可以达到我们的目的,如果l是奇数,那么r也肯定是奇数,所以答案就是(l + 1 >> 1 ) + (r + 1 >> 1),这里画个图就好了
#include <iostream>
#include <stack>
using namespace std;
typedef long long LL;
int main()
{
int n;
string str;
cin >> n;
cin >> str;
stack<char>stk;
int l = 0,r = 0;
for(auto &x : str){
if(stk.size()){
if(x == ')'){
if(stk.top() == '('){
stk.pop();
}else{
stk.push(x);
}
}
else{
stk.push(x);
}
}else{
stk.push(x);
}
}
while(stk.size())
{
if(stk.top() == ')'){
l ++;
}else{
r ++;
}
stk.pop();
}
if((l + r) % 2 != 0){
cout << -1 << endl;
}
else{
if(l % 2 == 0){
cout << (l + r >> 1 )<< endl;
}else{
int ans = l + 1 >> 1;
ans += r + 1 >> 1;
cout << ans << endl;
}
}
return 0;
}
题目描述:输入一个01字符串,有多少个字串可以操作k次,这里的k次不懂得话,看样例说明
思路:先统计出每段1和0的个数,如果k等于1的话,那么对于每一段就是1 + 2 + 3 + ....,求和公式,否则就是i就是从第k项开始,看第i项与第i-k项乘起来,具体看代码
#include <iostream>
#include <queue>
using namespace std;
typedef long long LL;
LL n,k;
int main()
{
string str;
cin >> n >> k;
cin >> str;
vector<int>v;
for(int i = 0;i < n;i ++){
int cnt = 0;
int j = i;
for(j = i;j < n;j ++){
if(str[j] == str[i]){
cnt ++;
}else{
break;
}
}
i = j - 1;
v.push_back(cnt);
}
LL res = 0;
if(k == 1){
for(auto &x : v){
res += 1ll*(x + 1)* x / 2;
}
}else{
k --;
for(int i = k;i < v.size();i ++)
{
res += 1ll*v[i] * v[i - k] ;
}
}
cout << res << endl;
return 0;
}
题目描述:小A每次可以任取 连续的 未被吞噬过的 三部分,将其中的黑暗全部吞噬,并获得中间部分的饱食度,小A想知道,自己能获得的饱食度最大值是多少
思路:dp[i]代表以第i项为结尾的最大值是多少,从第四项开始计算,小A可以吃当前这个黑暗数量dp[i - 3] + a[i],也可以不吃dp[i - 1]
dp[i] = max(dp[i - 3] + a[i],dp[i - 1]);
#include <iostream>
#include <queue>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
LL dp[N];
LL a[N];
int main()
{
int n;
cin >> n;
for(int i = 1;i <= n;i ++)
cin >> a[i];
dp[2] = a[2];
dp[3] = max(a[3],a[2]);
LL res = a[3];
for(int i = 4;i < n;i ++)
{
dp[i] = max(dp[i - 3] + a[i],dp[i - 1]);
res = max(res,dp[i]);
}
if(n == 3){
res = dp[2];
}
cout << res << endl;
return 0;
}
题目描述:略
思路:找到所有数的最大公约数,然后判断一下给的数能否整除最大公约数 (证明略),最大公约数我一般都是调用库函数,你也可以自己去写.
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
LL n,k;
LL t;
LL a[N];
int main()
{
cin >> n;
for(int i = 1;i <= n;i ++){
cin >> a[i];
}
t = a[1];
for(int i = 2;i <= n;i ++){
t = __gcd(a[i],t);
}
cin >> k;
while(k --){
LL x;
cin >> x;
if(x % t == 0){
cout << "Yes" << endl;
}else{
cout << "No" << endl;
}
}
return 0;
}
题目描述:找到一个最长链
思路:通过dp来求树的直径的一种变形,如果两个点可以到达也就是颜色不一样,那么 res = max(res,dp[u] + dp[j] + 1);dp[u] = max(dp[u],dp[j] + 1); 否则res = max(res,dp[u]);之前写过一个两种算法求树的直径的博客(写的不太好),有兴趣的同学可以看看https://blog.csdn.net/weixin_44235647/article/details/106661379
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int mod = 1e9 + 7;
typedef long long LL;
const int N = 1e6 + 10;
int n;
int w[N];
int h[N],e[N],ne[N],idx;
void add(int a,int b)
{
e[idx] = b,ne[idx] = h[a],h[a] = idx ++;
}
int res = 0;
int dp[N];
void dfs(int u,int fa)
{
for(int i = h[u];~i;i = ne[i])
{
int j = e[i];
if(j == fa) continue;
dfs(j,u);
if(w[u] == w[j]){
res = max(res,dp[u]);
}else{
res = max(res,dp[u] + dp[j] + 1);
dp[u] = max(dp[u],dp[j] + 1);
}
}
}
int main()
{
memset(h,-1,sizeof h);
cin >> n;
for(int i = 1;i <= n;i ++){
char c;
cin >> c;
if(c == 'R'){
w[i] = 1;
}else if(c == 'G'){
w[i] = 2;
}
}
for(int i = 0;i < n - 1;i ++)
{
int a,b;
cin >> a >> b;
add(a,b);
add(b,a);
}
dfs(1,0);
cout << res << endl;
return 0;
}
题目描述:这个考察应该是逆元,而B题考察的应该是卢卡斯定理
思路:
,然后注意一下精度,不懂得话,就全开long long
#include <iostream>
#include <algorithm>
using namespace std;
const int mod = 1e9 + 7;
typedef long long LL;
const int N = 1e6 + 10;
LL n,k,m;
LL t;
LL a[N];
LL qmi(LL a,LL b)
{
LL res = 1;
while(b){
if(b & 1) res = res * a % mod;
a = a * a % mod;
b = b >> 1;
}
return res;
}
int main()
{
scanf("%lld%lld%lld",&n,&m,&k);
LL s1 = 0,s2 = 0,s3 = 0;
for(int i = 1;i <= n;i ++){
int x;
scanf("%d",&x);
s1 += x;
}
for(int i = 1;i <= m;i ++){
int x;
scanf("%d",&x);
s2 += x;
}
for(int i = 1;i <= k;i ++){
int x;
scanf("%d",&x);
s3 += x;
}
s1 = s1 % mod;
s2 = s2 % mod;
s3 = s3 % mod;
LL sum = s1 * s2 % mod * s3 % mod;
LL sum1 = n * m % mod * k % mod;
printf("%lld",sum*qmi(sum1,mod - 2) % mod);
return 0;
}
题目描述:见题目说明
思路:先求出a,b的最近公共祖先t,然后统计根节点0到a的路径上所有不同的字母分别对应的总数,0到b的路径上所有不同的字母分别对应的总数,然后减去0到t的路径上所有不同的字母分别对应的总数,再把节点t对应的字母加上相应位置,如果字母出现的总数为偶数次那么加上答案,如果为奇数次,就加上奇数次-1,最终答案再加1; 倍增法求LCA
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int mod = 1e9 + 7;
typedef long long LL;
const int N = 1e6 + 10;
int n,q;
int w[N];
int h[N],e[N],ne[N],idx;
void add(int a,int b)
{
e[idx] = b,ne[idx] = h[a],h[a] = idx ++;
}
int dist[N];
int dp[N][30];
int f[N][20];
void dfs(int u,int fa)
{
for(int i = h[u];~i;i = ne[i])
{
int j = e[i];
if(j == fa) continue;
dist[j] = dist[u] + 1;
for(int i = 1;i <= 26;i ++)
dp[j][i] = dp[u][i];
int c = w[j];
dp[j][c] ++;
f[j][0] = u;
for(int i = 1;i <= 16;i ++)
{
int k = f[j][i - 1];
f[j][i] = f[k][i - 1];
}
dfs(j,u);
}
}
int lca(int a,int b)
{
if(dist[a] < dist[b]){
swap(a,b);
}
for(int i = 16;i >= 0;i --)
{
if(dist[f[a][i]] >= dist[b]){
a = f[a][i];
}
}
if(a == b){
return a;
}
for(int i = 16;i >= 0;i --)
{
if(f[a][i] != f[b][i]){
a = f[a][i];
b = f[b][i];
}
}
return f[a][0];
}
int main()
{
memset(h,-1,sizeof h);
cin >> n;
for(int i = 0;i < n - 1;i ++)
{
int a,b;
cin >> a >> b;
add(a,b);
add(b,a);
}
for(int i = 1;i <= n;i ++)
{
char c;
cin >> c;
w[i] = c - 'a' + 1;
}
dist[1] = 1;
dfs(1,0);
cin >> q;
while(q --)
{
int a,b;
cin >> a >> b;
int t = lca(a,b);
int arr[28] = {0};
for(int i = 1;i <= 26;i ++)
arr[i] += dp[a][i];
for(int i = 1;i <= 26;i ++)
arr[i] += dp[b][i];
for(int i = 1;i <= 26;i ++)
arr[i] -= dp[t][i] * 2;
arr[w[t]] ++;
int cnt = 0;
bool flag = false;
for(int i = 1;i <= 26;i ++)
{
if(arr[i] % 2 == 0){
cnt += arr[i];
}else if(arr[i]){
cnt += arr[i] - 1;
flag = true;
}
}
cout << cnt + flag << endl;
}
return 0;
}
题目描述:略
思路:m 除以二 上取整 判断与k的大小关系
#include <iostream>
using namespace std;
const int N = 110;
int t,n,m;
char g[N][N];
int main()
{
int n,m,k;
cin >> n >> m >> k;
m = m + 1 >> 1;
if(m <= k){
cout << "Yes" << endl;
}else{
cout << "No" << endl;
}
return 0;
}