蓝桥杯补题

方法技巧:

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博客

相关推荐
羊小猪~~9 分钟前
算法/力扣--字符串经典题目
c++·考研·算法·leetcode·职场和发展·哈希算法
小年糕是糕手16 分钟前
【35天从0开始备战蓝桥杯 -- Day7】
开发语言·jvm·数据库·c++·蓝桥杯
人道领域22 分钟前
LeetCode【刷题日记】:数组篇(1)含原理讲解
算法·leetcode·职场和发展
Alicx.10 小时前
dfs由易到难
算法·蓝桥杯·宽度优先
心软小念11 小时前
金三银四,全网最详细的软件测试面试题总结
软件测试·面试·职场和发展
软件测试媛12 小时前
软件测试常见的面试题(46道)
功能测试·面试·职场和发展
IronMurphy13 小时前
【算法三十一】46. 全排列
算法·leetcode·职场和发展
红云梦15 小时前
简历投了 100 份没回音?我给面试平台加了个“简历雷达“
人工智能·面试·职场和发展
studyForMokey18 小时前
【Android面试】Gradle专题
android·面试·职场和发展
编程一生20 小时前
面试问到的那些技术细节
面试·职场和发展