蓝桥杯补题

方法技巧:

1.进行循环暴力骗分,然后每一层的初始进行判断,如果已经不满足题意了,那么久直接continue,后面的循环就不用浪费时间了。我们可以把题目所给的等式,比如说有四个未知量,那么我们可以用其他的三个未知量进行确定表示最后一个未知量,这样我们就可以少一层暴力循环。

2.日期类的问题,我们可以直接枚举年份,判断闰年还是平年,然后根据这个选择二月份的时间。之后根据月份选择天数。

3.直接bfs或者dfs暴力,要尽可能地剪枝,比如说以后的情况就已经不满足了就要及时的return

4.记忆化,之前跑过的结果就直接return回之前的答案,不用那么麻烦的纠结是否可以实现。

5.注意一个问题,就是说,要范围,尤其是二分的时候。

6.注意如果最后一个数据还未进入答案的统计时候,在遍历完循环,要记得单独再加一个判断最后的一个数据是否可以更新答案。

7.充分挖掘,如果说不满足要求了,就可以提前退出了,写暴力循环的时候,一定要看能不能尽可能地优化。

【第十四届蓝桥杯考前速成】必考知识点及代码模板总结,看完至少多拿50分_蓝桥杯考前必看-CSDN博客

第八届:

复制代码
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n,m,a,b;
int oppo[7]={0,4,5,6,1,2,3};
bool st[7][7];
struct matrix{
    int c[7][7];
    matrix(){
        memset(c,0,sizeof(c));
    }
}A,res;

matrix operator * (matrix &x,matrix &y){
    matrix t;
    for(int i=1;i<=6;i++){
        for(int j=1;j<=6;j++){
            for(int k=1;k<=6;k++){
                
                t.c[i][j]=(t.c[i][j]+x.c[i][k]*y.c[k][j])%mod;
            }
        }
    }
    return t;
}
void fastpow(int k)
{
    for(int i=1;i<=6;i++)
    {
        res.c[1][i]=4;
    }
    for(int i=1;i<=6;i++){
        for(int j=1;j<=6;j++){
            if(st[i][oppo[j]]) A.c[i][j]=0;
            else A.c[i][j]=4;
        }
    }
    while(k){
        if(k&1) res=res*A;
        A=A*A;
        k>>=1;
    }
}
int main(){
    cin>>n>>m;
    while(m--){
        cin>>a>>b;
        st[a][b]=st[b][a]=1;
    }
    fastpow(n-1);
    int ans=0;
    for(int i=1;i<=6;i++){
        ans=(ans%mod+res.c[1][i]%mod)%mod;
    }
    cout<<ans<<"\n";
    return 0;
}

P8626 [蓝桥杯 2015 省 A] 灾后重建

是一个分治问题,还是不太会。目前只是知道暴力。

就是要构建一个生成树,使他们能给联通,代价就是构成这个生成树的最大边的权值。

每一次询问都会进行重新更新,也就是init。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

int N, M, Q;
const int maxM = 2e5;
const int maxN = 5e4 + 5;
int par[maxN];

//定义边 
struct edge {
	int begin, end, cost;
}edges[maxM];

bool cmp(edge x, edge y) {
	return x.cost<y.cost;
}

//并查集
int get_root(int a) {    //求根节点 
	if(par[a] != a) {
		par[a] = get_root(par[a]);
	}
	return par[a];
}

//查询是否在同一集合中 
bool query(int a,int b) {
     return get_root(a) == get_root(b);
}

//合并两个结点 
void merge(int a,int b) {
     par[get_root(a)] = get_root(b);
}

//每次询问都要初始化 
void init() {
	for(int i = 1;i <= N;i++) {
		par[i] = i;
	}
}

int solve(int l, int r, int k, int c) {
	init();
	for(int i = 0;i < M;i++) {
		int begin = edges[i].begin;
		int end = edges[i].end;
		int cost = edges[i].cost;
		
		if(get_root(begin) == get_root(end)) {   //该边的两个结点已经在同一个集合中 
			continue;
		}else {
			merge(begin, end);  //合并加边 
		}
		//每添加一条边都要判断一下已经满足条件,是就退出 
		bool flag = true;
		int parent = 0;
		//检查l到r中模k余c的点是否已经连通 
		for(int i = l;i <= r;i++) {
			if(i % k == c) {
				if(parent == 0) {
					parent = get_root(i);
				}else {
					if(parent != get_root(i)) {   //实际上就是检查这些结点是不是在同一个集合里 
						flag = false;
						break;
					}
				}
			}
		}
		if(flag) {
			cout<<cost<<endl;  //已经在同一个集合,说明已经连通 
			break;
		}
	}
	return 1;
}

int main() {
	cin>>N>>M>>Q;
	for(int i = 0;i < M;i++) {
		cin>>edges[i].begin>>edges[i].end>>edges[i].cost;
	} 
	sort(edges, edges + M, cmp);   //边从小到大排序 
	for(int i = 0;i < Q;i++) {
		int l, r, k, c;
		cin>>l>>r>>k>>c;
		solve(l, r, k, c);
	}
	return 0;
}

方格填数问题:

本质上就是一个dfs,然后在dfs过程中。

我们可以直接按照正常的顺序进行遍历,从左到右,在从上到下进行遍历。这样就可以满足我们所有的遍历情况,在遍历的过程中,如果check已经是false了那么我们就即使的进行break掉,直接进行下一层的遍历,同时也不会增加额外的开销。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int mp[10][10];
int ans = 0;
int dx[4] = {0, 0, -1, 1};
int dy[4] = {1, -1, 0, 0};

bool check(int i,int j){    //检查9宫格 
	for(int x=i-1;x<=i+1;x++){
		for(int y=j-1;y<=j+1;y++){
			if(abs(mp[x][y]-mp[i][j])==1)
				return false;
		}
	}
	return true;
}

int num[10] = {0};
int vis[10][10] = {0};

void dfs(int x, int y) {
    if (x==3&&y==4) {
        ans++;
        return;
    }

        // 尝试填充数字
        for (int j = 0; j < 10; j++) {
            if(num[j]==0){
    		mp[x][y]=j;  //填数
               num[j]=1;     
			if(check(x,y)){
            if(y==4)
				dfs(x+1,1);    //换行 
			else
				dfs(x,y+1);
			}
            num[j]=0;  
			mp[x][y]=100; 
        }
        }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    // 初始化地图
    for (int i = 0; i <= 5; i++) {
        for (int j = 0; j <= 6; j++) {
            mp[i][j] = 100;
        }
    }

    dfs(1, 2);
    cout << ans << "\n";

    return 0;
}

寒假作业:

这个也是一个dfs。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int ans;
int vis[20]={0};
int mp[100];
int check(int x)
{
    if(x>=3&&(mp[1]==0||mp[2]==0||mp[3]==0)) return 0;
    if(x>=6&&(mp[4]==0||mp[5]==0||mp[6]==0)) return 0;
    if(x>=9&&(mp[7]==0||mp[8]==0||mp[9]==0)) return 0;
    if(x>=12&&(mp[10]==0||mp[11]==0||mp[12]==0)) return 0;
    
    if(x>=3&&(mp[1]+mp[2]!=mp[3])) return 0;
    if(x>=6&&(mp[4]-mp[5]!=mp[6])) return 0;
    if(x>=9&&(mp[7]*mp[8]!=mp[9])) return 0;
    if(x>=12&&(mp[10]!=mp[12]*mp[11])) return 0;
    return 1;
}
void dfs(int x){
    if(x==14)
    {
        if(check(x))ans++;
        return;
    }
    for(int i=1;i<=13;i++)
    {
        if(vis[i]==0){
            mp[x]=i;
            vis[i]=1;
            if(check(x))dfs(x+1);
            mp[x]=0;
            vis[i]=0;
        }
    }
    
}


int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    ans=0;
    memset(mp,0,sizeof(mp));
    dfs(1);
    
    cout << ans << "\n";

    return 0;
}

密码脱落:

在这个问题中。

我们有两个问题需要考虑,一个是这个种子丢的地方不知道,另外一个丢了几个也不知道。

那么其实本质上就是说,非连续的子序列相同问题。我们要前后对称,那么我们就需要找到一个最长的子序列,这个子序列是回文的。如果我们暴力的寻找,会很麻烦时间复杂度一定会炸掉。之后呢我们可以构建一个反串,就是说,这个反串和正串进行寻找最长的公共子序列,那么这样复杂度就是n2满足我们的要求。

cpp 复制代码
#include <iostream>
#define ll long long
#include <algorithm>
#include <string>
#include <string.h>
#include <cstdio>

using namespace std;
int dp[1010][1010];
int main(){
	string str1,str2;
	while(cin>>str1){
		memset(dp,0,sizeof(dp));
		str2=str1;
		int len=str1.size();
		reverse(str2.begin(),str2.end());		//翻转串
		for(int i=1;i<=len;i++){				
			for(int j=1;j<=len;j++){
				if( str1[i-1] == str2[j-1] ) dp[i][j]=dp[i-1][j-1]+1;
				else{
					dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
				}
			}
		}
		cout<< len-dp[len][len] <<endl;
	}
	return 0;
}

迷宫问题:

这个问题的思路是这个样子的。

1.从终点方向跑路线,这样可以直接更新重点到每一点的最短距离。

2.从正向进行构建路线,优选选择字段序小的字母,这个字母之后进行找到下一个字母,同时这两个位置之间的距离恰好就是1,这样就是我们正确的最小路径。

cpp 复制代码
#include <iostream>
#include <algorithm>
#include <string>
#include <string.h>
#include <queue>
using namespace std;
char a[40][60];                                                 //存图
int nextx[4] = { 1,0,0,-1 }, nexty[4] = { 0,-1,1,0 };           //D<L<R<U      字典序直接把方向数组处理好就可以了
int dist[40][60];                                               //定义一个dist数组,用来存放各点到终点的最短距离
char dir[4] = { 'D','L','R','U' };                             
bool check(int x, int y) {
    return x > 0 && y > 0 && x <= 50 && y <= 50 && a[x][y] == '0'&&dist[x][y] == -1;
}
void bfs() {                                                    //BFS扫一遍,求出各点到终点的最短距离
    queue<pair<int, int> >q;
    memset(dist, -1, sizeof(dist));
    dist[30][50] = 0;
    q.push({ 30,50 });
    while (!q.empty()) {
        pair<int ,int> t = q.front();
        q.pop();
 
        for (int i = 0; i < 4; i++) {
            int newx = t.first + nextx[i];
            int newy = t.second + nexty[i];
            if (check(newx, newy)) {
                dist[newx][newy] = dist[t.first][t.second] + 1;
                q.push({ newx,newy });
            }
        }
 
    }
}
 
int main() {
 
    for (int i = 1; i <= 30; i++)
        for (int j = 1; j <= 50; j++)
            cin >> a[i][j];
    bfs();
 
    int x = 1, y = 1;                                                                       //从起点开始遍历
    string res;                                                                             //存答案
    while (x != 30 || y != 50) {
        for (int i = 0; i < 4; i++) {
            int newx = x + nextx[i];
            int newy = y + nexty[i];
            if (newx > 0 && newy > 0 && newx <= 50 && newy <= 50 && a[newx][newy] == '0'&&dist[newx][newy]==dist[x][y]-1) {
                x = newx, y = newy;
                res += dir[i];
                break;
            }
        }
    }
    cout << res << "\n";
    return 0;
}

方格分割:

我们就是从(3,3)中心的位置进行搜索的,然后如果走到了边界,说明就是一种方案。然后因为我们四个方向如果走到一个点后,那么我们可能是可能会重复的。所以答案是/4.

这个点和对称点同时要置为1.

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

short a[1005][1005];
int dx[5]={0,0,-1,1};
int dy[5]={1,-1,0,0};
int ans;
void dfs(int x,int y){
    if(x==0||y==0||x==6||y==6)
    {
        ans++;
        return;
    }
    for(int i=0;i<4;i++)
    {
        int xx=x+dx[i];
        int yy=y+dy[i];
        if(a[xx][yy]==0)
        {
            a[xx][yy]=1;
            a[6-xx][6-yy]=1;
            dfs(xx,yy);
            a[xx][yy]=0;
            a[6-xx][6-yy]=0;
        }
    }
}


void solve()
{
    a[3][3]=1;
    ans=0;
    dfs(3,3);
    cout<<ans/4<<"\n";
    
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int T;T=1;
    //cin>>T;
    while(T--){
        solve();
    }
}

正则问题,

我们清晰的发现也是一个dfs问题,直接进行递归就行。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

short a[1005][1005];
int dx[5]={0,0,-1,1};
int dy[5]={1,-1,0,0};
int ans;
void dfs(int x,int y){
    if(x==0||y==0||x==6||y==6)
    {
        ans++;
        return;
    }
    for(int i=0;i<4;i++)
    {
        int xx=x+dx[i];
        int yy=y+dy[i];
        if(a[xx][yy]==0)
        {
            a[xx][yy]=1;
            a[6-xx][6-yy]=1;
            dfs(xx,yy);
            a[xx][yy]=0;
            a[6-xx][6-yy]=0;
        }
    }
}


void solve()
{
    a[3][3]=1;
    ans=0;
    dfs(3,3);
    cout<<ans/4<<"\n";
    
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int T;T=1;
    //cin>>T;
    while(T--){
        solve();
    }
}

包子凑数问题。

首先根据两个数论定理。

ax+by=z 有解的情况,只能是,gcd(a,b)可以被z整数。

如果ab互质的话,说明了z是任何1的倍数,那么ab就可以表示所有的数。

如果不是互质的话,根据一个定理,他所不能表达的数字一定在 a*b-a-b内。那么我们就直接判断是否可以得到这个区间的所有数字。这是一个完备空间,我们就直接进行完全背包的暴力。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
/**
 测试用例
 2
 3 5

 答案
 4
 */
typedef long long LL;
const int N = 1e6 + 5;

LL f[N];  //表示凑出j个包子的方法总数
int a[N]; //每种规格中包子的数量
int ans;  //组装不出来的包子个数

//最大公约数,辗转相除法
int gcd(int a, int b) {
    if (b == 0) return a;
    return gcd(b, a % b);
}

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];

    //赛瓦维斯特定理 :  两个互质数a,b表示不出来的最大数字是 a∗b−a−b
    //下面排序后找出极小值与次小值,它们的乘积再减去极小和次小,就是极限值
    sort(a + 1, a + 1 + n);
    int m1 = a[1], m2 = a[2]; //最小和次小
    int M = m1 * m2 - m1 - m2;

    //求出所有数字的最大公约数
    int g = a[1];
    for (int i = 2; i <= n; i++) g = gcd(g, a[i]);

    /*裴蜀定理:如果所有数字的最大公约数大于1,那么必然存在无法表示出的数字。
     不互质栗子:
     比如3 和 6      两种规格,能组装的就是 3,6,9,12,15,这个变化就是它们的最大公约数3。
     比如3 和 6 和 9 三种规格, 能组装的也是 3,6,9,12,15,这个变化就是它们的最大公约数3。
     此时 ,类似于 1,2,4,5,7,...之类的数字均是无法凑出的,有无穷多个。

     互质栗子:
     比如 3 和  4   两种规格, 能组装的就是 3,4,6,7,8,9,10,11,12...., 根据赛瓦维斯特定理,我们知道,最大的不能组装的数字是3*4-3-4=5
     比如 3 和  4 和 6 三种规格,因为3,4就能组装出5以上的所有数字,所以我们只需要从最小a[1]到 M 中查找即可。
    */
    if (g > 1) {
        cout << "INF" << endl; // cout << -1 << endl; //青少组要求输出-1
        return 0;
    }

    /**
      完全背包
      f[j]表示凑出j个包子的方法总数,简单说就是如果f[j]>0就凑得出,f[j]=0就凑不出。
      递推式 f[j]=f[j−第i种蒸笼包子数]+1 (f[j−第i种蒸笼包子数]>=1)
      当j−第i种蒸笼包子数是可以凑成的,那么只需对其+第i种蒸笼包子数就可以凑成j个包子数。
     */
    f[0] = 1; //  0个包子这个状态是合法的,是可以到达的状态。而且只能是一种方案,就是不管是哪种规格,一概不要
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= M; j++)
            if (j >= a[i] && f[j - a[i]]) f[j]++;

    //枚举每个可能的数字,如果这个数字存在1种以上的方案,就是可以凑出,否则就是无法凑出
    for (int i = 1; i <= M; i++)
        if (!f[i]) ans++;

    //输出答案
    cout << ans << endl;
    return 0;
}

油漆面积

其本质就是一个二位差分二位前缀和问题。

那么我们要注意的是,因为他所告诉你的不是格子的坐标,而是坐标系的坐标。

那么就需要进行特殊表示。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

short a[10005][10005];
void solve()
{
   int k;
    cin>>k;
    for(int i=1;i<=k;i++)
    {
        int x1,y1,x2,y2;
        cin>>x1>>y1>>x2>>y2;
        a[x1][y1]+=1;
        a[x2][y1]-=1;
        a[x1][y2]-=1;
        a[x2][y2]+=1;
    }
    int ans=0;
    for(int i=0;i<=10000;i++)
    {
        for(int j=0;j<=10000;j++)
        {
            a[i][j] = (i > 0 ? a[i-1][j] : 0) + (j > 0 ? a[i][j-1] : 0) - (i > 0 && j > 0 ? a[i-1][j-1] : 0) + a[i][j];
            if(a[i][j]) ++ans;
        }
    }
    cout<<ans<<"\n";
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int T;T=1;
    //cin>>T;
    while(T--){
        solve();
    }
}
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define int long 
int run(int x)
{
    if(x%400==0) return 1;
    if(x%4==0&&x%100!=0) return 1;
    return 0;
}
int a[20]={0,31,28,31,30,31,30,31,31,30,31,30,31};

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t=6;
    int ans=0;
    for(int i=2000;i>=1901;i--)
    {
        int be=12;
        int en=1;
        if(run(i)) a[2]=29;
        else a[2]=28;
        for(int j=be;j>=en;j--)
        {
            int bee=a[j];
            int enn=1;
            for(int k=bee;k>=enn;k--)
            {
                if(t==0){
                    ans++;
                }
                t=(t-1+7)%7;
            }
            
        }
    }
    cout<<ans<<"\n";
}

乘积尾零

这个问题应该不可以用每次乘完,去除完了末尾0然后进行继续计算,还是有可能会发生溢出问题。那么我们直接分割,分成有多少个2和5.然后取min,这样最后的答案就是我们的要的答案。

三体攻击

一个三维进行的计算问题。最后进行二分判断,第一个爆炸的飞船。

全球变暖

一个bfs,我们注意要先将下一个点标志城true,这样的话就不会造成这个点被加入多次,造成时间上的超时。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int dx[5]={0,0,1,-1};
int dy[5]={1,-1,0,0};
int n;
int mp[1005][1005]={0};
bool vis[1005][1005];
struct node{
  int x,y;
};
int bfs(int xxx,int yyy)
{
    queue<node>q;
    q.push({xxx,yyy});
    int flag=1;
    while(!q.empty()){
        auto [x,y]=q.front();
        q.pop();
        vis[x][y]=true;
        int num=0;
        for(int i=0;i<4;i++){
            int xx=x+dx[i];
            int yy=y+dy[i];
            if(xx>=1&&xx<=n&&yy>=1&&yy<=n&&mp[xx][yy]){
              num++;
              if(vis[xx][yy]==false) 
              {vis[xx][yy]=true;q.push({xx,yy});}
            }
        }
        if(num==4) flag=0;
    }
    return flag;
        
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            char c;cin>>c;
            if(c=='#') mp[i][j]=1;
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)
        {
            if(!vis[i][j]&&mp[i][j]){
                ans+=bfs(i,j);
            }
        }
    }
    cout<<ans<<"\n";
    
}

付账问题:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
 
long long a[500010];
 
int main() {
	int n;
	long long s;
	cin >> n >> s;
	for (int i = 0; i < n; i++) {
		cin >> a[i];
	}
    //开始贪心选择
	sort(a, a + n); //排序,从小到大
	double avg = 1.0 * s / n;
	double sum = 0.0;
	for (int i = 0; i < n; i++) {
		if (a[i] * (n - i) < s) { //把钱全拿出的人
			sum += (a[i] - avg) * (a[i] - avg);
			s -= a[i]; //更新还差多少钱
		} else { //不需要把钱全拿出的人。剩下的人中,钱最少的人都可以达到cur_avg
			double cur_avg = 1ASEE.0 * s / (n - i); //注意这里的s是还差多少钱
			sum += (cur_avg - avg) * (cur_avg - avg) * (n - i); //如果这个人有钱付,那么后面的人一定也能付,所以直接乘后面的人数(n - i)即可
			break;
		}
	}
	printf("%.4f", sqrt(sum / n));
 
	return 0;
}

颜色平衡树:求子树的个数。字数满足每一个颜色的子节点数量一样。

直接进行暴力bfs进行计算。

cpp 复制代码
#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>

using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> C(n + 1); // 存储每个节点的颜色
    vector<vector<int>> children(n + 1); // 存储每个节点的子节点列表

    for (int i = 1; i <= n; ++i) {
        int ci, fi;
        cin >> ci >> fi;
        C[i] = ci;
        if (fi != 0) {
            children[fi].push_back(i);
        }
    }

    int ans = 0;

    for (int u = 1; u <= n; ++u) {
        unordered_map<int, int> colorCount;
        queue<int> q;
        q.push(u);

        while (!q.empty()) {
            int node = q.front();
            q.pop();
            colorCount[C[node]]++;
            for (int child : children[node]) {
                q.push(child);
            }
        }

        bool valid = true;
        int cnt = -1;
        for (auto& pair : colorCount) {
            if (cnt == -1) {
                cnt = pair.second;
            } else {
                if (pair.second != cnt) {
                    valid = false;
                    break;
                }
            }
        }

        if (valid) {
            ans++;
        }
    }

    cout << ans << endl;

    return 0;
}

博弈论

cpp 复制代码
using namespace std;
#include<vector>
#include<iostream>
#include<unordered_map>
typedef long long ll;

class Solution {
        
    public:
        unordered_map<string,bool> mp;// 记录各种状态的胜利,失败情况
        bool check(string s) {
            // 只剩下一个O,为必输态
            int cnt=0;
            for(const auto &c:s) {
                if(c=='O') cnt++;
            }
            return cnt==1;
        }
        // 第二行先下的人是必输的。
        // 由于小蓝优先下,因为传入的是XOOO,XXOO,OXOO,OXXO,是小蓝已经下棋的状态
        // 小蓝已经下了棋,所以小乔具有主动权。 
        // 又因为第二行第一个下棋的人必输,所以小乔在第一行应该让自己输,这样小乔才会赢 
        // 因为每一个人都以最优策略下棋,所以小乔会争取第一行输
        // dfs("XOOO")表示以这个棋盘开始下棋,小乔的输赢(算法默认优先找输) 
        // 返回true,表示小乔第一行只能赢,那么第二行先手就是小乔,小蓝必赢 
        // 返回false,表示小乔拥有第一行输的优先权,那么小乔第二行在最优策略下就一定赢,小蓝就必输
        // 最终可以知道小乔第一行赢对应小蓝最终赢(两行下完)
        // 小乔第一行可以输对应小蓝最终输两行下完)
        // 最后强调,对于小乔的优先策略就是输!!!,因为dfs的结果只针对棋盘只有第一行时小乔的输赢。 
        bool dfs(string s) {
            if(mp.count(s)) return mp[s];// 避免重复计算
            if(check(s)) {
                // 说明当前这个人只有一个空位下,走到这一步的人必输
                mp[s]=false;
                return false;
            }
            int n=s.size();
            // 下一个
            for(int i=0; i<n; i++) {
                if(s[i]=='O') {
                    string temp=s;
                    temp[i]='X';
                    if(dfs(temp)) {
                        mp[s]=false;
                        return false;
                    }
                }
            }

            // 下两个
            for(int i=0; i<n; i++) {
                if(i<n-1&&s[i]=='O'&&s[i+1]=='O') {
                    string temp=s;
                    temp[i]='X';
                    temp[i+1]='X';
                    if(dfs(temp)) {
                        mp[s]=false;
                        return false;
                    }
                }
            }
            // 优先找输,所以实在不可能输了,在返回赢 
            mp[s]=true;
            return true;
        }
};

char to_char(bool ans) {
    return ans?'V':'L';
}

int main() {
    Solution solution;
    // dfs表示小乔能不能在第一行输掉 
    bool r1=solution.dfs("XOOO"); 
    bool r2=solution.dfs("XXOO"); 
    bool r3=solution.dfs("OXOO"); 
    bool r4=solution.dfs("OXXO"); 
    cout << to_char(r1) << to_char(r2) << to_char(r3) << to_char(r4);
    return 0;
}

括号序列

暴力:

al表示还需要多少个左括号 ar表示还需要多少个右括号

l表示已经有了多少个左括号,r表示已经有了多少个右括号

每次往下遍历的时候,需要保证当前的左括号数一定要大于右括号的数量

cpp 复制代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_set>
using namespace std;

int n;
string s;
unordered_set<string> ret;

void dfs(int l,int r,int al,int ar,int idx,string cur){
    if(idx==n){
        if(!al&&!ar)
            ret.insert(cur);
        return;
    }
    if(al)
        dfs(l+1,r,al-1,ar,idx,cur+'(');
    if(ar&&l>r)
        dfs(l,r+1,al,ar-1,idx,cur+')');
    if(s[idx]=='(')
        dfs(l+1,r,al,ar,idx+1,cur+'(');
    else if(l>r)
        dfs(l,r+1,al,ar,idx+1,cur+')');
}

int main(){
    cin>>s;
    n=s.size();
    int al=0,ar=0,l=0;
    for(char c:s){
        if(c=='('){
            l++;
        }
        else if(c==')'){
            if(l==0)
                al++;
            else{
                l--;
            }
        }
    }
    ar=l;
    dfs(0,0,al,ar,0,"");
    cout<<ret.size();
}

迷宫

cpp 复制代码
#include <iostream>
#include <algorithm>
#include <string>
#include <string.h>
#include <queue>
using namespace std;
char a[40][60];                                                 //存图
int nextx[4] = { 1,0,0,-1 }, nexty[4] = { 0,-1,1,0 };           //D<L<R<U      字典序直接把方向数组处理好就可以了
int dist[40][60];                                               //定义一个dist数组,用来存放各点到终点的最短距离
char dir[4] = { 'D','L','R','U' };                             
bool check(int x, int y) {
    return x > 0 && y > 0 && x <= 50 && y <= 50 && a[x][y] == '0'&&dist[x][y] == -1;
}
void bfs() {                                                    //BFS扫一遍,求出各点到终点的最短距离
    queue<pair<int, int> >q;
    memset(dist, -1, sizeof(dist));
    dist[30][50] = 0;
    q.push({ 30,50 });
    while (!q.empty()) {
        pair<int ,int> t = q.front();
        q.pop();
 
        for (int i = 0; i < 4; i++) {
            int newx = t.first + nextx[i];
            int newy = t.second + nexty[i];
            if (check(newx, newy)) {
                dist[newx][newy] = dist[t.first][t.second] + 1;
                q.push({ newx,newy });
            }
        }
 
    }
}
 
int main() {
 
    for (int i = 1; i <= 30; i++)
        for (int j = 1; j <= 50; j++)
            cin >> a[i][j];
    bfs();
 
    int x = 1, y = 1;                                                                       //从起点开始遍历
    string res;                                                                             //存答案
    while (x != 30 || y != 50) {
        for (int i = 0; i < 4; i++) {
            int newx = x + nextx[i];
            int newy = y + nexty[i];
            if (newx > 0 && newy > 0 && newx <= 50 && newy <= 50 && a[newx][newy] == '0'&&dist[newx][newy]==dist[x][y]-1) {
                x = newx, y = newy;
                res += dir[i];
                break;
            }
        }
    }
    cout << res << "\n";
    return 0;
}

RSA加密:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll p,q,e,ans;
ll n = 1001733993063167141,d = 212353;
ll C = 20190324;

bool prime(ll x) {
    for(ll i = 2;i <= sqrt(x); i++) {
        if(x % i == 0) {
            return false;
        }
    }
    return true;
}

ll gcd(ll a,ll b) {
    return b?gcd(b,a%b):a;
}

ll gcd_Ex(ll a,ll b,ll &x,ll &y) {   //ax+by=c的整数解 
    if(b==0) {
        x=1;
        y=0;
        return a;
    }
    ll x1,y1;
    ll gcd=gcd_Ex(b,a%b,x1,y1);  //bx+(a%b)y=gcd(a,b)有整数解x1,y1; 
    x=y1;y=x1-a/b*y1;
    return gcd;
}

ll mod_reverse(ll a,ll b) {   //求解ax%b==1 
    ll d,x,y;
    d=gcd_Ex(a,b,x,y);   //ax+by=gcd(a,b)有整数解x,y
    if(d==1) {
        return (x%b+b)%b;
    }else {             //无解 
        return -1;
    }
}

ll fast_mul(ll a, ll b, ll mod){  //快速求解a*b%mod 
    ll ans = 0;
    while(b) {
        if(b&1) {
            ans = (ans + a) % mod;
        }
        a=(a<<=1) % mod;
        b >>= 1;
    }
    return ans;
}

ll pow_mod(ll a,ll b,ll mod) {   //快速求解a^b%mod
    ll res=1,base=a%mod;
    while(b) {
        if(b&1) {
            res=fast_mul(res,base,mod);
        }
        base=fast_mul(base,base,mod);
        b >>= 1;
    }
    return res;
}

int main() {
    //求解p,q 
    /*for(ll i=1000;;i++) {
        if(n%i==0&&prime(i)&&prime(n/i)&&gcd(d,(i-1)*(n/i-1))==1) {
            p=i;
            q=n/i;
            break;
        }
    }*/
    p=891234941,q=1123984201;
    ll t=(p-1)*(q-1);
    e=mod_reverse(d,t);
    ll x=pow_mod(C,e,n);
    cout<<x;
    return 0;
}

外卖模拟:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    priority_queue<int,vector<int>,greater<int>> h[100010]; //为每一家店创造一个优先队列(小顶对)
    int n, m, t;
    cin >> n >> m >> t;
    for(int i = 1; i<=m; i++){
        int x, y;
        cin >> x >> y;
        h[y].push(x);//把时间点存入这家店的队列中
    }
    int cnt = 0;
    for(int i = 1; i<=n; i++){
        int pri = 0; //"优先级"
        int lastget = 0; //上一次订单的时间
        bool in = false; //是否在"优先推荐"中
        while(!h[i].empty()){
            int x = h[i].top(); //订单时间
            h[i].pop();
            if(lastget!=x) pri-=(x-lastget-1);//如果不是同一个时间点多个订单的话,减去没有订单的那些时间需要减去的"优先级"
            if(pri<0) pri = 0; //可能小于零,设置成零
            if(in&&pri<=3) in = false; //如果在推荐里,但是此时"优先级"小于等于3,踢出推荐中
            pri+=2; //拿到两点"优先级"
            lastget = x; //更新上一次时间
            if(pri>5) in = true; //如果此时"优先级"大于3,踢出推荐中
        }
              //注意的是,这里需要先判断是否被踢出推荐,然后再加上2,
      
              //因为加入的条件是大于5,退出的条件是小于等于3,如果此时小于等于3了,但是加上2之后不小于3了,按照程序,符合"在推荐中+没有小于等于3",不会被踢出去,
              //但是由于在这些空余的时间里,已经出了推荐榜,如果再进,需要大于5,此时没有达到在加入的条件,没有在推荐榜中
      
              //这里,由于要看的是时间T,但是T有可能不是最后一次收到订单的时间,需要额外判断,方法同上
        if(lastget!=t) pri-=(t-lastget);
        if(in&&pri<=3) in = false;
        if(in){
            cnt++;
        }
    } 
    cout << cnt;
    return 0;
}

修改数组:v

cpp 复制代码
#include<bits/stdc++.h>

#define rep(i, a, b) for(int i = a; i < b ; i++)

using namespace std;

const int N = 1e6 + 10;
int fa[N]; //并查集存储当前 "节点族" 最大还有哪个节点未用上
int n;

int find(int x)
{
    if(fa[x] != x) fa[x] = find(fa[x]); //向上查找祖先节点,同时进行 "路经压缩"
    return fa[x]; //返回最大的可以用的节点
}

int main()
{
    cin >> n;
    //1.初始化并查集
    rep(i, 1, N) //注意此时,并查集初始化取决于 数组中元素A的大小
        fa[i] = i;
    
    //2.对于每个节点,加入并查集,更新最大未使用的元素
    int x;
    rep(i, 1, n + 1)
    {
        scanf("%d", &x);
        x = find(x); //找到当前最大未使用的元素
        printf("%d ", x);
        fa[x] = x + 1; //当前节点已经用过了 -> 往后偏移 -
        //如果是最新的,那么会直接输出当前元素,反之,输出之前记录的可以使用的最大元素
    }
            
    return 0;
}

状态压缩:

cpp 复制代码
#include <iostream>
using namespace std;
int n,m,k;long long dp[1<<21],a[105];
int main()
{cin>>n>>m>>k;
for(int i=1;i<=n;i++)
 for(int j=1;j<=k;j++)
{int x;cin>>x;
a[i]|=(1<<(x-1));
}
for(int i=1;i<(1<<m);i++)dp[i]=1e9;
for(int d=0;d<(1<<m);d++)
  for(int i=1;i<=n;i++)dp[d|a[i]]=min(dp[d|a[i]],dp[d]+1);
  long long ans=dp[(1<<m)-1];
cout<<(ans==1e9?-1:ans);
  return 0;
}

倍数问题:

暴力枚举

cpp 复制代码
#include <bits/stdc++.h>

using namespace std;

int main() {
    int n, k;
    cin >> n >> k;
    int nums[n];

    // 读取输入的 n 个整数并存储到数组中
    for(int i = 0; i < n; i++) {
        cin >> nums[i];
    }

    // 对数组进行排序
    sort(nums, nums + n);

    // 初始化结果变量为 0
    int ans = 0;

    // 三重循环遍历数组中所有可能的三个数的组合
    for (int i = n - 1; i >= 2; i--) {
        for (int j = i - 1; j >= 1; j--) {
            for (int t = j - 1; t >= 0; t--) {
                // 计算当前三个数的和
                int sum = nums[i] + nums[j] + nums[t];
                // 如果当前和是 k 的倍数,更新结果为当前和和原结果中的较大值
                if (sum % k == 0) {
                    ans = max(ans, sum);
                }
                // 如果当前和小于结果,跳出内层循环
                if (sum < ans) {
                    break;
                }
            }
            // 如果当前三个数的和已经小于结果,跳出内层循环
            if(nums[i] + nums[j] + nums[j - 1] < ans) {
                break;
            }
        }
        // 如果当前三个数的和已经小于结果,跳出外层循环
        if(nums[i] + nums[i - 1] + nums[i - 2] < ans) {
            break;
        }
    }

    // 输出结果
    cout << ans << endl;

    return 0;
}

尽可能地平均

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
 
long long a[500010];
 
int main() {
    int n;
    long long s;
    cin >> n >> s;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    //开始贪心选择
    sort(a, a + n); //排序,从小到大
    double avg = 1.0 * s / n;
    double sum = 0.0;
    for (int i = 0; i < n; i++) {
        if (a[i] * (n - i) < s) { //把钱全拿出的人
            sum += (a[i] - avg) * (a[i] - avg);
            s -= a[i]; //更新还差多少钱
        } else { //不需要把钱全拿出的人。剩下的人中,钱最少的人都可以达到cur_avg
            double cur_avg = 1.0 * s / (n - i); //注意这里的s是还差多少钱
            sum += (cur_avg - avg) * (cur_avg - avg) * (n - i); //如果这个人有钱付,那么后面的人一定也能付,所以直接乘后面的人数(n - i)即可
            break;
        }
    }
    printf("%.4f", sqrt(sum / n));
 
    return 0;
}

包子凑数:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
/**
 测试用例
 2
 3 5

 答案
 4
 */
typedef long long LL;
const int N = 1e6 + 5;

LL f[N];  //表示凑出j个包子的方法总数
int a[N]; //每种规格中包子的数量
int ans;  //组装不出来的包子个数

//最大公约数,辗转相除法
int gcd(int a, int b) {
    if (b == 0) return a;
    return gcd(b, a % b);
}

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];

    //赛瓦维斯特定理 :  两个互质数a,b表示不出来的最大数字是 a∗b−a−b
    //下面排序后找出极小值与次小值,它们的乘积再减去极小和次小,就是极限值
    sort(a + 1, a + 1 + n);
    int m1 = a[1], m2 = a[2]; //最小和次小
    int M = m1 * m2 - m1 - m2;

    //求出所有数字的最大公约数
    int g = a[1];
    for (int i = 2; i <= n; i++) g = gcd(g, a[i]);

    /*裴蜀定理:如果所有数字的最大公约数大于1,那么必然存在无法表示出的数字。
     不互质栗子:
     比如3 和 6      两种规格,能组装的就是 3,6,9,12,15,这个变化就是它们的最大公约数3。
     比如3 和 6 和 9 三种规格, 能组装的也是 3,6,9,12,15,这个变化就是它们的最大公约数3。
     此时 ,类似于 1,2,4,5,7,...之类的数字均是无法凑出的,有无穷多个。

     互质栗子:
     比如 3 和  4   两种规格, 能组装的就是 3,4,6,7,8,9,10,11,12...., 根据赛瓦维斯特定理,我们知道,最大的不能组装的数字是3*4-3-4=5
     比如 3 和  4 和 6 三种规格,因为3,4就能组装出5以上的所有数字,所以我们只需要从最小a[1]到 M 中查找即可。
    */
    if (g > 1) {
        cout << "INF" << endl; // cout << -1 << endl; //青少组要求输出-1
        return 0;
    }

    /**
      完全背包
      f[j]表示凑出j个包子的方法总数,简单说就是如果f[j]>0就凑得出,f[j]=0就凑不出。
      递推式 f[j]=f[j−第i种蒸笼包子数]+1 (f[j−第i种蒸笼包子数]>=1)
      当j−第i种蒸笼包子数是可以凑成的,那么只需对其+第i种蒸笼包子数就可以凑成j个包子数。
     */
    f[0] = 1; //  0个包子这个状态是合法的,是可以到达的状态。而且只能是一种方案,就是不管是哪种规格,一概不要
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= M; j++)
            if (j >= a[i] && f[j - a[i]]) f[j]++;

    //枚举每个可能的数字,如果这个数字存在1种以上的方案,就是可以凑出,否则就是无法凑出
    for (int i = 1; i <= M; i++)
        if (!f[i]) ans++;

    //输出答案
    cout << ans << endl;
    return 0;
}

枚举

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

short a[1005][1005];
int dx[5]={0,0,-1,1};
int dy[5]={1,-1,0,0};
int ans;
void dfs(int x,int y){
    if(x==0||y==0||x==6||y==6)
    {
        ans++;
        return;
    }
    for(int i=0;i<4;i++)
    {
        int xx=x+dx[i];
        int yy=y+dy[i];
        if(a[xx][yy]==0)
        {
            a[xx][yy]=1;
            a[6-xx][6-yy]=1;
            dfs(xx,yy);
            a[xx][yy]=0;
            a[6-xx][6-yy]=0;
        }
    }
}


void solve()
{
    a[3][3]=1;
    ans=0;
    dfs(3,3);
    cout<<ans/4<<"\n";
    
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int T;T=1;
    //cin>>T;
    while(T--){
        solve();
    }
}

// #include <iostream>
// using namespace std;

// const int to[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};//方向数组
// const int N = 6;//边上的格子数,不是点数,点数要+1
// bool map[N + 1][N + 1];  //表示点
// int ans;       //方法数

// void dfs(int x, int y) {
//     if (x == 0 || y == 0 || x == 6 || y == 6) {
//         ans++;
//         return;
//     }
//     for (int i = 0; i < 4; i++) {
//         //注意这里好像只能建临时的坐标,而不能建全局变量
//         int tx = x + to[i][0];
//         int ty = y + to[i][1];
//         //不用担心越界,因为到边界就会return
//         if (map[tx][ty] == false) {
//             map[tx][ty] = true;
//             map[N - tx][N - ty] = true;//由于是关于起点中心对称的,所以每次搜索会涉及两个点
//             dfs(tx, ty);
//             map[tx][ty] = false;
//             map[N - tx][N - ty] = false;
//         }
//     }
// }

// int main(void) {
//     map[3][3] = true;//起点置为真
//     dfs(3, 3);//开始搜索
//     printf("%d\n", ans/4);
//     return 0;
// }

正则 问题:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
int re(int ans){
    char c;
    while(cin>>c){
        if(c == '\r' || c == '\n') return ans;
        else if(c == 'x') ans ++;
       else if(c == '(') ans += re(0);
        else if(c == ')') return ans;
        else if(c == '|') return max(ans, re(0));
    }
    return ans;
} 
int main() {
    cout<<re(0);
    return 0;
}

方格填数

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int mp[10][10];
int ans = 0;
int dx[4] = {0, 0, -1, 1};
int dy[4] = {1, -1, 0, 0};

bool check(int i,int j){    //检查9宫格 
    for(int x=i-1;x<=i+1;x++){
        for(int y=j-1;y<=j+1;y++){
            if(abs(mp[x][y]-mp[i][j])==1)
                return false;
        }
    }
    return true;
}

int num[10] = {0};
int vis[10][10] = {0};

void dfs(int x, int y) {
    if (x==3&&y==4) {
        ans++;
        return;
    }

        // 尝试填充数字
        for (int j = 0; j < 10; j++) {
            if(num[j]==0){
            mp[x][y]=j;  //填数
               num[j]=1;     
            if(check(x,y)){
            if(y==4)
                dfs(x+1,1);    //换行 
            else
                dfs(x,y+1);
            }
            num[j]=0;  
            mp[x][y]=100; 
        }
        }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    // 初始化地图
    for (int i = 0; i <= 5; i++) {
        for (int j = 0; j <= 6; j++) {
            mp[i][j] = 100;
        }
    }

    dfs(1, 2);
    cout << ans << "\n";

    return 0;
}

寒假作业:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int ans;
int vis[20]={0};
int mp[100];
int check(int x)
{
    if(x>=3&&(mp[1]==0||mp[2]==0||mp[3]==0)) return 0;
    if(x>=6&&(mp[4]==0||mp[5]==0||mp[6]==0)) return 0;
    if(x>=9&&(mp[7]==0||mp[8]==0||mp[9]==0)) return 0;
    if(x>=12&&(mp[10]==0||mp[11]==0||mp[12]==0)) return 0;
    
    if(x>=3&&(mp[1]+mp[2]!=mp[3])) return 0;
    if(x>=6&&(mp[4]-mp[5]!=mp[6])) return 0;
    if(x>=9&&(mp[7]*mp[8]!=mp[9])) return 0;
    if(x>=12&&(mp[10]!=mp[12]*mp[11])) return 0;
    return 1;
}
void dfs(int x){
    if(x==14)
    {
        if(check(x))ans++;
        return;
    }
    for(int i=1;i<=13;i++)
    {
        if(vis[i]==0){
            mp[x]=i;
            vis[i]=1;
            if(check(x))dfs(x+1);
            mp[x]=0;
            vis[i]=0;
        }
    }
    
}


int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    ans=0;
    memset(mp,0,sizeof(mp));
    dfs(1);
    
    cout << ans << "\n";

    return 0;
}

里外世界:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define int long long

const int INF = 1e18;

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, k;
    cin >> n >> k;

    vector<int> a(n + 1), b(n + 1);
    for (int i = 1; i <= n; ++i) cin >> a[i];
    for (int i = 1; i <= n; ++i) cin >> b[i];

    vector<vector<int>> dp(n + 1, vector<int>(2, -INF));
    dp[1][0] = a[1]; // 初始在表世界1号点

    for (int i = 2; i <= n; ++i) {
        // 从表世界i-1到表世界i
        if (dp[i-1][0] != -INF) {
            dp[i][0] = dp[i-1][0] + a[i];
        }
        // 从里世界i-1到表世界i(跃迁)
        if (dp[i-1][1] >= k) {
            dp[i][0] = max(dp[i][0], dp[i-1][1] + a[i] - k);
        }

        // 从里世界i-1到里世界i
        if (dp[i-1][1] != -INF) {
            dp[i][1] = dp[i-1][1] + b[i];
        }
        // 从表世界i-1到里世界i(跃迁)
        if (dp[i-1][0] >= k) {
            dp[i][1] = max(dp[i][1], dp[i-1][0] + b[i] - k);
        }
    }

    cout << max(dp[n][0], dp[n][1]) << '\n';

    return 0;
}

bfs

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define int long long

int num;
int n,m;
char mp[1000][1000];
int vis[501][501];
int dis[501][501];
int dx[5]={0,0,1,-1};
int dy[5]={1,-1,0,0};
int fa[260005];
map<array<int,2>,int>id;

int _find(int x){
    if(x==fa[x]) return x;
    else{
        fa[x]=_find(fa[x]);
        return fa[x];
    }
}
void _union(int x,int y)
{
    int fax=_find(x);
    int fay=_find(y);
    fa[fax]=fay;
}
void bfs(int bex,int bey)
{
    queue<array<int,2>>q;
    q.push({bex,bey});
    vis[bex][bey]=1;
    int faa=_find(id[{bex,bey}]);
    while(q.size()){
        auto [x,y]=q.front();q.pop();
        vis[x][y]=1;
        for(int i=0;i<4;i++){
            int xx=x+dx[i];
            int yy=y+dy[i];
            if(xx<1||xx>n||yy<1||yy>m) continue;
            if(vis[xx][yy]==1) continue;
            if(mp[xx][yy]=='#') continue;
            vis[xx][yy]=1;
            q.push({xx,yy});
            _union(id[{bex,bey}],id[{xx,yy}]);
        }
    }

}
void solve() {
    cin>>n>>m;
    num=0;

    for(int i=1;i<=260000;i++) fa[i]=i;
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>mp[i][j];
            id[{i,j}]=++num;
        }
    }

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(vis[i][j]==0&&mp[i][j]=='.'){
                bfs(i,j);
            }
        }
    }

    int Q;
    cin>>Q;
    while(Q--){
        int x1,x2,y1,y2,enx,eny;
        cin>>x1>>y1>>x2>>y2>>enx>>eny;

        int dis1=abs(x1-enx)+abs(y1-eny);
        int dis2=abs(x2-enx)+abs(y2-eny);
        int cnt1=0;
        int cnt2=0;
        for(int i=0;i<4;i++)
        {
            int xx=x1+dx[i];
            int yy=y1+dy[i];
            if(xx<1||xx>n||yy<1||yy>m) cnt1++;
            else if(mp[xx][yy]=='#') cnt1++;
        }

        for(int i=0;i<4;i++)
        {
            int xx=x2+dx[i];
            int yy=y2+dy[i];
            if(xx<1||xx>n||yy<1||yy>m) cnt2++;
            else if(mp[xx][yy]=='#') cnt2++;
        }
        if(cnt1==3&&dis1==1&&dis2!=1){
            cout<<"No\n";
            continue;
        }
        if(cnt2==3&&dis1!=1&&dis2==1){
            cout<<"No\n";
            continue;
        }
        if(dis1%2==dis2%2&&_find(id[{x1,y1}])==_find(id[{enx,eny}])&&_find(id[{x2,y2}])==_find(id[{enx,eny}])){
            cout<<"Yes\n";
        }else{
            cout<<"No\n";
        }

    }


}

signed main() {
    int T;T=1;
    //cin>>T;
    while(T--) {
       solve();
    }
}

组合数问题:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+100;
const int mod=1e9+7;
int n;
int fast_pow_mod(int a,int b,int mod){
    int res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
int C(int a,int b){
    if(a<b) return 0;
    int res=1;
    for(int i=1,j=a;i<=b;j--,i++){
        res=res*j%mod;
        res=res*fast_pow_mod(i,mod-2,mod)%mod;
    }
    return res;

}
int fact(int a)
{
    int res=1;
    for(int i=a;i>=2;i--){
        res=res*i%mod;
    }
    return res;
}
void solve(){
    int n;cin>>n;
    int res=C(n/3,n/2-n/3)*C(n-n/3,n/2-n/3)%mod*fact(n/3)%mod*fact(n-n/3)%mod;
    cout<<res<<"\n";
    return;
}
signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;t=1;
    //cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

小红的染色期望:

有 nnn 个白色小球排成一排。小红每次将++随机++选择两个相邻的白色小球,将它们染成红色。小红将持续这个操作直到无法操作,请你计算小红操作次数的期望。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e6+100;
const int mod=1e9+7;
int n;
int fast_pow_mod(int a,int b,int mod){
    int res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
int C(int a,int b){
    if(a<b) return 0;
    int res=1;
    for(int i=1,j=a;i<=b;j--,i++){
        res=res*j%mod;
        res=res*fast_pow_mod(i,mod-2,mod)%mod;
    }
    return res;

}
int fact(int a)
{
    int res=1;
    for(int i=a;i>=2;i--){
        res=res*i%mod;
    }
    return res;
}
int dp[maxn]={0};
int pre[maxn]={0};
void solve(){
    int n;cin>>n;
    dp[0]=0;dp[2]=1;
    dp[1]=0;
    pre[2]=1;
    for(int i=3;i<=n;i++)
    {
        int p=fast_pow_mod(i-1,mod-2,mod);
        dp[i]=(dp[i]+pre[i-2]*2%mod*p%mod)%mod;
        dp[i]=(dp[i]+1)%mod;
        pre[i]=(pre[i-1]+dp[i])%mod;
    }
    cout<<dp[n]<<"\n";
}
signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;t=1;
    //cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

极坐标排序:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e6+100;
const int mod=1e9+7;
int fast_pow_mod(int a,int b,int mod){
    int res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
int C(int a,int b){
    if(a<b) return 0;
    int res=1;
    for(int i=1,j=a;i<=b;j--,i++){
        res=res*j%mod;
        res=res*fast_pow_mod(i,mod-2,mod)%mod;
    }
    return res;

}
int fact(int a)
{
    int res=1;
    for(int i=a;i>=2;i--){
        res=res*i%mod;
    }
    return res;
}
const int N=2e+5+100;
struct point{
    int x,y;
}P[N],xl[N];
bool cmp(point a,point b){
    return a.x*b.y>a.y*b.x;
}
int cross(int x1,int y1,int x2,int y2){
    return x1*y2-x2*y1;
}

void solve(){
    int ans=LONG_LONG_MAX;
    int n;
    cin>>n;
    for(int i=1;i<n;i++)
    {
        cin>>P[i].x>>P[i].y;
    }
      for(int i=0;i<n;i++)
    {
        int k=0;
        for(int j=0;j<n;j++)
        {
            if(i!=j)
            {
                xl[k].x=P[j].x-P[i].x;
                xl[k].y=P[j].y-P[i].y;
                k++;
            }
        }
        sort(xl,xl+k,cmp);
        for(int j=0;j<k-1;j++)
        {
            //cout<<abs(xl[j].x*xl[j+1].y-xl[j+1].x*xl[j].y)<<endl;
            ans=min(ans,abs(xl[j].x*xl[j+1].y-xl[j+1].x*xl[j].y));
        }
    }
    printf("%.3lf",double(ans)/2);
}
signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;t=1;
    //cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

想与不是0的可以建立边:

cpp 复制代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
const int N = 1e5 + 10,mod=1e9+7;
const int INF=0x3f3f3f3f;
typedef long long ll;
typedef pair<int, int> pii;
int T;
int n;
ll p[N+65],Size[N+65];
int find(int x)
{
    if(p[x]!=x)p[x]=find(p[x]);
    return p[x];
}
void merge(int a,int b)
{
    int pa=find(a),pb=find(b);
    if(pa!=pb)
    {
        Size[pb]+=Size[pa];
        p[pa]=pb;
    }
}
int main()
{
    cin>>T;
    while(T--)
    {
        cin>>n;
        for(int i=1;i<=n+64;i++)p[i]=i,Size[i]=1;
        for(int i=n+1;i<=n+64;i++)Size[i]=0;
        for(int i=1;i<=n;i++)
        {
            ll x;
            cin>>x;
            for(int j=0;j<=63;j++)
                if(x>>j&1)
                    merge(i,n+j+1);
        }
        ll ans=0;
        for(int i=n+1;i<=n+64;i++)ans=max(ans,Size[i]);
        cout<<ans<<endl;
    }
    return 0;
}

分解质因数:

cpp 复制代码
//分解质因子 
#include <iostream> 
using namespace std;
int main()
{
    int num;
    cin >> num;
    cout << num << "=";
    for (int i = 2; i <= num; i++)  //循环查找判断质因数
    {
        while (num % i == 0)    //若i为num的质因数,则输出i
        {
            cout << i;
            num /= i;    //对num除以i后的数求取质因数
            if (num != 1)//判断num是否除尽 
                cout << "*";
        }
    }
    cout << endl;
    return 0;
}

质数筛子:

cpp 复制代码
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

void sieve(int n) {
vector<bool> is_prime(n + 1, true);
is_prime[0] = is_prime[1] = false;

for (int i = 2; i <= sqrt(n); ++i) {
if (is_prime[i]) {
for (int j = i * i; j <= n; j += i) {
is_prime[j] = false;
}
}
}

for (int i = 2; i <= n; ++i) {
if (is_prime[i]) {
cout << i << " ";
}
}
cout << endl;
}

int main() {
int n;
cout << "请输入一个数字:";
cin >> n;
sieve(n);
return 0;
}

李白打酒:

(第十三届蓝桥杯省赛)I:李白打酒加强版(动态规划)_李白打酒 动态规划-CSDN博客

相关推荐
寒页_7 小时前
2025年第十六届蓝桥杯省赛真题解析 Java B组(简单经验分享)
java·数据结构·经验分享·算法·蓝桥杯
汇太浪9 小时前
第十六届蓝桥杯大赛软件赛省赛 Python 大学 B 组 部分题解
蓝桥杯
邪神与厨二病9 小时前
2025蓝桥杯python A组题解
数据结构·c++·python·算法·蓝桥杯·单调栈·反悔贪心
ExtractStars11 小时前
2025 蓝桥杯省赛c++B组个人题解
c++·蓝桥杯
小徐Chao努力11 小时前
【蓝桥杯】第十六届蓝桥杯 JAVA B组记录
java·蓝桥杯
梭七y12 小时前
【力扣hot100题】(089)最长有效括号
算法·leetcode·职场和发展
柒_汐12 小时前
第十五届蓝桥杯C/C++B组省赛真题讲解(分享去年比赛的一些真实感受)
c语言·c++·蓝桥杯·真题·省赛
lzb75912 小时前
蓝桥杯单片机刷题——ADC测量电位器的电压
单片机·蓝桥杯
nuo53420213 小时前
第十六届蓝桥杯 省赛C/C++ 大学B组
c语言·c++·算法·蓝桥杯·图论
ん贤14 小时前
2021第十二届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组
c语言·c++·蓝桥杯