0
点赞
收藏
分享

微信扫一扫

复试专业前沿问题问答合集8-1——CNN、Transformer、TensorFlow、GPT

夏天的枫_ 03-26 12:00 阅读 2

92. 递归实现指数型枚举 - AcWing题库

#include <bits/stdc++.h>
using namespace std;
const int N=17;
int n;
bool vis[N];//记录某一个数是否出现过
void dfs(int dep){
  // if(vis[dep])continue;//没有这一句 因为一定不会有已经选过的数
  if(dep==n+1){
    for(int i=1;i<=n;i++){
      if(vis[i])cout<<i<<' ';
    }
    cout<<'\n';
    return ;//记得要return
  }
  vis[dep]=1;//选上
  dfs(dep+1);//去判断下一个数
  vis[dep]=0;//不选
  dfs(dep+1);//去判断下一个数
}
int main(){
  cin>>n;
  dfs(1);
  return 0;
}
//输入3 输出 1 12 123 2 23 3  特点:长度不固定 不会往前找

94. 递归实现排列型枚举 - AcWing题库 

#include <bits/stdc++.h>
using namespace std;
const int N=17;
int n;
bool vis[N]={};//记录某一个数是否出现过
vector<int>ans;
void dfs(int dep){//这里的dep表示的是够多少个数
  if(dep==n+1){
    for(auto i:ans)cout<<i<<' ';
    cout <<'\n';
    return ;
  }
  for(int i=st;i<=n;i++){
    if(vis[i])continue;
    vis[i]=1;
    ans.push_back(i);
    dfs(dep+1);//这里要是搜索下一个位置 一定要是dep+1
    vis[i]=0;
    ans.pop_back();
  }
}//这样的意思是从第一个数开始搜 答案一定要够n个数才能输出
int main(){
  cin>>n;
  dfs(1);
  return 0;
}
//输入3 输出123 132 213 231 321 312 特点长度固定,可以往前找

 93. 递归实现组合型枚举 - AcWing题库
 

#include <bits/stdc++.h>
using namespace std;
const int N=100;
int a[N];
int n,m;//n个数中选择m个
int vis[N];
void dfs(int dep,int st){//st数组是为了保证顺序每次只往后面找
    if(dep==m+1){//选够m个数了 该选第m+1个数了
        for(int i=1;i<=n;i++){
            if(vis[i]==1)cout<<a[i]<<" ";
        }
        cout<<'\n';
        return ;
    }
    for(int i=st;i<=n;i++){
        if(!vis[i]){
        vis[i]=1;
        dfs(dep+1,i+1);//这里是i+1 因为第i个数字做出判断之后下次要判断的应该是它后面的数
        vis[i]=0;
        }
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)a[i]=i;
    dfs(1,1);
    return 0;
}
输入:5 3
输出 123 124 125 134 135 145 234 235 245 345 特点长度固定,不会往前找


dfs与for循环结合 长度固定 可以往前找 (可以用st限制)

dfs不与for循环结合 长度不固定 不能往前找 

95. 费解的开关 - AcWing题库

#include <bits/stdc++.h>
using namespace std;
const int N = 6;
int xx[N] = {-1, 0, 1, 0, 0};//上 右 下 左 中
int yy[N] = {0, 1, 0, -1, 0};
char g[N][N], backup[N][N];


// 这个操作是把(x, y)以及上下左右的灯都变成相反的颜色
void turn (int x, int y){
    for (int i = 0; i < 5; i ++ )
    {
        int a = x + xx[i], b = y + yy[i];

        //如果在边界外边,直接忽略即可
        if (a < 0 || a >= 5 || b < 0 || b >= 5) continue;

        g[a][b] ^= 1;   //异或,不同的时候就变成相反的数
        //同0异1
    }
}

int main(){
    int n;scanf("%d", &n);
    while(n -- ){
        // 按行输入,把每一行当成一个字符串
        for (int i = 0; i < 5; i ++ ) cin >> g[i];
        int res = 0x3f3f;
        // 这里我们枚举了第一行的32种按法,不用管是亮是灭,把第一行所有情况都按一遍
        // 按每种情况的第一行,去遍历接下来的行
        // 枚举32种第一行的按法只是可能会减少步数,如果直接从第二行开始答案一定是固定的了,找不到最优解或者可能没有解

//枚举第一行的意义是:不需要在意第一行的灯是灭是暗,只需把第一行的按法枚举一遍,也就是我们说的 “操作”,
//每个位置都有两种选择,按(用1表示)或者不按(用0表示),遍历这32种操作引发的情况,
//每一次再通过res = min(res, step);把最小步数存一下,就能找到最优解
        for (int op = 0; op < 32; op ++ ){//枚举第一行每一种按法 //好好想想这里为什么要是<32:11111是31 
//是说我们输入的已知的是第一行灯亮或暗的状态,而我们枚举的32种是我们对灯的操作,按还是不按。
            // 我在对这种情况操作的时候,得先备用一下
            // 把原始数组备份一下,然后操作g,操作完了还原,然后再操作
            memcpy(backup, g, sizeof g);//用于复制数组

            int step = 0;

            // 第一行的按法(在这里 1 表示按了, 0 表示不按),这里只是为了输出第一行按完之后的状态
            for (int i = 0; i < 5; i ++ )
                if (op >> i & 1)   // 数字2 对应了 00010 表示第2个位置的按一下
                                  // 00010 >> 1 & 1  是1 所以turn(0, 1) 就是第一行第二个位置
                {                // 数字3 对应了00011 表示第1 和第2个位置的按一下
                    step ++ ;
                    turn (0, i);//使得第一行的形式改变 一定有一种 正好按住原状态中的暗灯
                }

            // 然后通过第一行按完之后的状态,按234行
            for (int i =0; i < 4; i ++ )
                for (int j = 0; j < 5;j ++ )
                    if (g[i][j] == '0'){
                        step ++;
                        turn (i + 1, j);  // 如果这个位置是灭的,就按下一行对应的位置
                    }

            bool dark = false;
            for (int j = 0; j < 5; j ++ )
                if (g[4][j] == '0'){
                    dark = true;
                    break;
                }


            // 对于32种情况的这一种,如果所有的全亮就记录下步数(事实上只记录了最后一行是否dark)
            if (!dark) res = min(res, step);
            memcpy (g, backup, sizeof g);
        }

        if(res > 6) res = -1;
        cout << res << '\n';

    }
    return 0;
}

重点:

1.为什么五个位置是2^4却枚举到32 因为最差的情况是00000是0 最好的情况是11111是31 所以要到32 

2.位运算中 ^1相当于取反 同0异1

3.把第一行的所有按法都枚举一遍 一定有一种是刚好与第一行的情况向对应的 不断更新答案即可

4,如果最后一行还有暗的话说明没救了

5.memcpy(a,b,sizeof b)是复制数组的用法

116. 飞行员兄弟 - AcWing题库

//一个把手改变,会使所在行列的所有把手全部反转
//特点:①在最优解里面每个把手只按一次,按两次没有区别

//②按的顺序无关紧要,最终取决于这个把手按的次数!!!

//思考这个题可以递推出来吗?  答案是:很难
//可以想一想,前面的题都是通过某种顺序,每一次都是影响一个灯泡,但是这个题
//不能使用前面的办法,因为操作一次会影响好多灯泡。所以想一想朴素做法

//我们发现这个题的数据范围很小,所以尝试用暴力解决ac
//暴力思路:①16个开关,所有开关的状态数量想一想是多少? 答案是2^16!

//状态数量即最大操作次数2^16(65536),既然也不大,那就①枚举所有的方案,
// int 是2^32
//然后按照这个方案来操作
//②如果可以实现把手全开,证明此方案合法
//③然后统计这个方案里面需要操作的把手数量
//④在所有能按的开关数量里取一个最小值

//输出方案注意:若两种方案步数相同,按字典序(先按横坐标排序,再按纵坐标排序)

#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;

typedef pair<int,int> PII;
const int N=5;
char g[N][N],backup[N][N];


//映射函数
int get(int x,int y){
    return x*4+y;//返回第x行第y列上的数是多少
}

void turn_one(int x,int y){
    if(g[x][y]=='+') g[x][y]='-';
    else g[x][y]='+';
}

void turn_all(int x,int y){
    for(int i=0;i<4;i++){
        turn_one(x,i);//关闭这一行所有的 
        turn_one(i,y);//关闭这一列的全部
		                  //xy被关闭了两次 相当于没变 
    }
    turn_one(x,y);//对xy也要改变 
}

int main(){
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
            cin>>g[i][j];
    
    vector<PII> res;//这是记录方案所需要的结构

    //枚举所有的方案
    for(int op=0;op<(1<<16);op++){//枚举每一种方案 1代表我们要去操作那个灯
//1111 1111 1111 1111           n个位置就到2^n

        vector<PII> temp;//temp里面存的是方案
        //先备份一下,为什么?因为这又不是最终方案,我们要把所有方案都试一遍,求最少的
        memcpy(backup,g,sizeof g);

        //枚举16个位置,进行操作
        for(int i=0;i<4;i++)
            for(int j=0;j<4;j++)
                if(op>>get(i,j)&1) //如果当前位置是1(我们在方案中准备操作)的话--get的作用就是返回二进制数中那一位是第几位,从而判断是否为1
                {
                    temp.push_back({i,j});
                    //按一下开关
                    turn_all(i,j);
                }
                
        //判断所有灯泡是否全亮
        bool has_closed=false;
        for(int i=0;i<4;i++)
            for(int j=0;j<4;j++)
                if(g[i][j]=='+') has_closed=true;//有一个关闭就不行

        if(has_closed==false)
        {
            //如果方案为空或者他的操作数大于我们刚存好的新的方案,那么就修改它
            if(res.empty()||res.size()>temp.size()) res=temp;//vector容器的操作
        }
        //还原回来,供下一个方案操作
        memcpy(g,backup,sizeof g);
    }
    
    //因为没说无解,所以可以猜想一下一定有解
    cout<<res.size()<<'\n';
    //这里的迭代函数就是一种简便写法,不要误解
    //另外原题下标从1开始,所以下面加1了
    for(auto op:res) cout<<op.x+1<<" "<<op.y+1<<'\n';
    return 0;
}

本题仍然是遍历所有的方案 

1208. 翻硬币 - AcWing题库

#include <bits/stdc++.h>
using namespace std;
const int N=107;
char change(char &ch){
    if(ch=='*') return 'o';
    return '*';
}

char a[N];
char b[N];
int main(){
  //读不进去可以尝试 cin>>s+1,cin>>s,cin.ignore(),getline(cin,a),cin.getline(a,N);
    cin.getline(a,N);
    cin.getline(b,N);
    // cin>>(a+1);
    // cin>>(b+1);
    int n = strlen(a);
    int step = 0;
    for(int i = 0; i < n; i++){
        if(a[i] != b[i]){
            a[i] = change(a[i]);
            if(i+1 < n) {
                a[i+1] = change(a[i+1]);
            }
            step++;
        }
    }
    cout << step;
    return 0;
}

 读入数据:

1.char s[N] cin>>s+1; / cin>>s;

2.cin.ignore();getline(cin,a);

3.cin.getline(a,N);

790. 数的三次方根 - AcWing题库

#include <bits/stdc++.h> 
using namespace std;
 
double n,l,r,mid;
double eps=1e-8;//精度/100
 
bool check(double mid,int m){//m次根下
    double c=1;
    while(m){
        c=c*mid;//s次根 
        m--;//c是mid的3次方 
    }
//要与别的条件扯上关系 在这里就是与n本身扯上关系
    if(c>=n)//如果mid的3次方大于等于n 
        return true;//还可以再小 
    else//如果mid的3次方下雨n 
        return false;//需要更大 
}
 
int main(){
    int m=3;
    cin>>n;
//设置二分边界
    l=-10000,r=10000;//设置大一点 
//实数二分
    while (l + eps < r)
    {//mid是a可以的值 
        double mid = (l + r) / 2;
        if (check(mid,m))r = mid;
        else l = mid;
    }
    //一般使用print
    //printf("%x.yf",n)
    //其中X是固定整数长度,小数点前的整数位数不够,会在前面补0
    //y是保留小数位数,不够补零
    printf("%.6lf",l);
    return 0;
}

796. 子矩阵的和 - AcWing题库 

#include <bits/stdc++.h>
using namespace std;
const int N=1007;
//二维前缀和:预处理要与a[i][j]相关联
//预处理:s[i][j]=s[i-1][j]+s[i][j-1]+a[i][j]-s[i-1][j-1]  -重复 
//实现:(x1,y1)以左上角 (x2,y2)为右上角
//实现:  s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1][y2]      +重复

//一维差分: 预处理b[i]=a[i]-a[i-1]    b[i]改变后面的数都改 

//二维差分:
//预处理: 
//void insert(int x1,int y1,int x2,int y2){               +重复 
//b[x1][y1]+=c;
//b[x2+1][y1]-=c;
//b[x1][y2+1]-=c;
//b[x2][y2]+=c;
//实现:
//b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1]               -重复 
int a[N][N];
int pre[N][N];
int main(){
	int n,m,q;cin>>n>>m>>q;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
		}
	}
    for(int i=1;i<=n;i++){
    	for(int j=1;j<=m;j++){
    		pre[i][j]=pre[i-1][j]+pre[i][j-1]+a[i][j]-pre[i-1][j-1];
		}
	}
	while(q--){
		int x1,y1,x2,y2;cin>>x1>>y1>>x2>>y2;
		cout<<pre[x2][y2]-pre[x1-1][y2]-pre[x2][y1-1]+pre[x1-1][y1-1]<<'\n';
	}
	return 0;
} 

730. 机器人跳跃问题 - AcWing题库 

//递推解方程
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;

int n;
int h[N];
double p[N];//存放2的次幂
//E(i+1)==2Ei-H(i+1)
//E(1)=2X-H(1)
//X>=(E(1)+H(1))/2
int main(){
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> h[i];

    p[0] = 1;//2^0=1

    double res = 0;//假设最开始的能量值为res  最小值 
    for(int i = 1; i <= n; i++){
        p[i] = p[i - 1] * 2;//存2的次幂
        res += (1.0 / p[i]) * h[i];//最后Ei的能量值为0正好用完的时候最小
    }

    cout << ceil(res) << '\n';

    return 0;
}

1221. 四平方和 - AcWing题库 

 

//写法1:纯暴力
#include <bits/stdc++.h>
using namespace std;
const int N = 5e6+7;
int n;
signed main () {
    int n;cin>>n;
    for(int a=0;a*a<=n;a++){
    	for(int b=a;a*a+b*b<=n;b++){
    		for(int c=b;a*a+b*b+c*c<=n;c++){
    			int temp=n-(a*a+b*b+c*c);
    			int d=sqrt(temp);
    			if(d*d==temp&&d>=c){//记得这里取sqrt时还要判断一下是不是平方数
    				printf("%d %d %d %d",a,b,c,d);
    				return 0;
				}
			}
		}
	}
	return 0;
}
//模拟哈希表
#include <bits/stdc++.h>
using namespace std;
const int N = 5e6+7;
int n;
struct sum{
	int s,c,d;
	bool operator<(const sum &t)const{
		if(s!=t.s)return s<t.s;
		if(c!=t.c)return c<t.c;
		return d<t.d;
	}
}sum[N];
int m=1;
signed main () {
    int n;cin>>n;
    for(int c=0;c*c<=n;c++){
    	for(int d=c;c*c+d*d<=n;d++){
    		sum[m++]={c*c+d*d,c,d};
		}//存数
	}
	sort(sum,sum+m);
	for(int a=0;a*a<=n;a++){
		for(int b=a;a*a+b*b<=n;b++){
			int t=n-a*a-b*b;
			int l=1,r=m;
			while(l<r){
				int mid=l+r>>1;
				if(sum[mid].s>=t)r=mid;
				else l=mid+1;//尽量向左边找 
			}
			if(sum[l].s==t){
				printf("%d %d %d %d\n",a,b,sum[l].c,sum[l].d);
				return 0;
			}
		}
	}
	return 0;
}
//库函数哈希表
#include <bits/stdc++.h>
#define int long long
#define x first
#define y second
using namespace std;

const int N = 5e6+7;
int n;
unordered_map<int, pair<int,int> > has;

signed main() {
    cin >> n;

    for (int c = 0; c * c <= n; c++) {
        for (int d = c; c * c + d * d <= n; d++) {
            int t = c * c + d * d;
            if (has.count(t) == 0) has[t] = {c, d};
        }
    }

    for (int a = 0; a * a <= n; a++) {
        for (int b = a; a * a + b * b <= n; b++) {
            int t = n - a * a - b * b;
            if (has.count(t)) {
                printf("%d %d %d %d\n", a, b, has[t].x, has[t].y);
                return 0;
            }
        }
    }

    return 0;
}
//模拟哈希表
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N = 5e6 + 10;
int n;
int has[N * 2];//小技巧,避免pair,r[c^2+d^2]=c;可以推导出d

int main(){
    cin >> n;
    memset(has, -1, sizeof has);

    for(int c = 0; c * c <= n; c++){
        for(int d = c; c * c + d * d <= n; d++){
            int t = c * c + d * d;
            if(has[t] == -1){
                has[t] = c;//只存下来c就可以了
            }
        }
    }

    for(int a = 0; a * a <= n; a ++){
        for(int b = a; a * a + b * b <= n; b++){
            int t = n - a * a - b * b;
            int c = has[t];
            if(has[t] == -1) continue;
            int d = sqrt(t - c * c);//不用判是不是平方数 因为一定是
            printf("%d %d %d %d\n", a, b, c, d);
            return 0;
        }
    }
    return 0;
}

1227. 分巧克力 - AcWing题库 

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+7;
int n,k;
int h[N],w[N];
//mid是问的输出的答案 在return时候的条件尽量要与题目中的别的变量扯上关系
bool check(int mid){//表示巧克力的最大边长 
    int cnt=0;
	for(int i=1;i<=n;i++){//对于第i个巧克力 
		cnt+=(h[i]/mid)*(w[i]/mid);//长上能分出来的份数*宽上能分出来的份数
	}
	if(cnt>=k)return true;
	else return false;
}
void solve() {
    cin>>n>>k;//n个巧克力 分出来k块  求最大边长 
    for(int i=1;i<=n;i++){
    	cin>>h[i]>>w[i];
	}
	int l=0,r=max(*max_element(h+1,h+n+1),*max_element(w+1,w+n+1)) ;
	while(l<r){
		int mid=(l+r+1)>>1;
		if(check(mid))l=mid;
		else r=mid-1;
	}
	cout<<r;
}
signed main() {
    int t = 1;
    while (t--) solve();
    return 0;
}

99. 激光炸弹 - AcWing题库 

#include <iostream>
using namespace std;
const int N = 5010;
int n = 5005,m,r;
int sum[N][N];
int get (int x1,int y1,int x2,int y2) {
    return sum[x2][y2] - sum[x1 - 1][y2] - sum[x2][y1 - 1] + sum[x1 - 1][y1 - 1];
}
int main () {
    cin >> m >> r;
    int maxx,maxy;
    for (int i = 1;i <= m;i++) {
        int x,y,w;
        cin >> x >> y >> w;
        x++,y++;
        maxx = max (maxx,x);
        maxy = max (maxy,y);
        sum[x][y] += w;
    }
    for (int i = 1;i <= n;i++) {
        for (int j = 1;j <= n;j++) sum[i][j] += sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1];
    }//预处理前缀和数组
    int ans = 0;
    for (int i = 1;i + r - 1 <= n;i++) {//右端点是i+r-1
        for (int j = 1;j + r - 1 <= n;j++) ans = max (ans,get (i,j,i + r - 1,j + r - 1));
    }
     if (r >= maxx && r >= maxy) {
        cout << sum[n][n] << '\n';
        return 0;
    }//特判了
    cout << ans << '\n';
    return 0;
}

1230. K倍区间 - AcWing题库 

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=100007;
int a[N];
int cnt[N];//开一个cnt数组 cnt[i]表示的是截止到目前为止余数是i的数有多少个
signed main(){
	int  n,k;cin>>n>>k;
	for(int i=1;i<=n;i++){
	cin>>a[i];
	a[i]+=a[i-1]; //前缀和
}

    int ans=0;
    for(int r=0;r<=n;r++){//枚举右端点 右端点也可能是0
      ans+=cnt[a[r]%k];//前面余数为a[r]%k的cnt[a[r]%k]个数都能做左端点
      //计算前面和  同余的个数 可以做左端点
      cnt[a[r]%k]++;//加上自身
    }
    cout<<ans;
	return 0;
} 

 

 

 

举报

相关推荐

0 条评论