Camp算法刷题记录2

文章目录

          • 503 A-B数对
          • 504 数位计算
          • 602 01序列 (好题)
          • 601 bfs练习
          • 整除光棍
          • 507 Luris的游戏
          • 506 完美数
          • 407 饿饿饭饭暑假狂欢
          • 406 循环子串
          • 604 碰撞2
          • 606巨大的牛棚
          • 607 高利贷
          • 701 背包
          • 703 简单的异或问题
          • 605优美!最长上升子序列
          • 704 子串的循环挪动
          • 挖地雷

503 A-B数对
#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include 
using namespace std;
map<int, int>mp;
int main(void) {
	int n, c, x;
	cin >> n >> c;
	for (int i = 1; i <= n; ++i) {
		cin >> x;
		mp[x]++;
	}
	int ans = 0;
	for (auto t : mp) {
		ans = ans + t.second * mp[t.first - c];
	}
	cout << ans;
	return 0;
}
504 数位计算
#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include 
using namespace std;
typedef long long  ll;
const int mod = 998244353;
ll qmul(ll x, ll y) {   //返回x*y模mod后的值。转化成二进制加法(快速加)
	ll ret = 0;
	while (y) {
		if (y & 1)    //二进制下,若y末尾为1
			ret = (ret + x) % mod;    //则加x*1,并将x左移1位。
		x = (x << 1) % mod;    //若y末尾为0,则加x*0,并将x左移1位,即直接左移。
		y = y >> 1;    //准备计算y前一位的值
	}
	return ret;
}
int main(void) {
	ll n,i;
	int t = 10;
		cin >> n;
		if (n < 10) {
			cout << n;
			return 0;
		}
		ll ans = 0;
		for (i = 10; i <= n; i = i * 10) {
			//ans = (ans + ((1 + i - i / 10) % mod) * ((i - i / 10) % mod) / 2) % mod;
			if ((1 + i - i / 10) % 2 == 0)
				ans = ans + qmul((1 + i - i / 10) / 2, i - i / 10);
			else ans = ans + qmul(1 + i - i / 10, (i - i / 10) / 2);
		}
		//ans = ans + ((1 + (n - i / 10 + 1))%mod) * ((n - i / 10 + 1)%mod) / 2;
		if((1 + n - i / 10+1)%2==0)
			ans = ans + qmul((1 + n - i / 10+1) / 2, n - i / 10 + 1);
		else ans = ans + qmul(1 + n - i / 10+1 , (n - i / 10 + 1)/2);
		cout << ans%mod<<"\n";
	
	return 0;
}

两个大数取模,每个先取模,再相乘后取模,应该也是可以的,写成上面注释掉了的代码也ac了

602 01序列 (好题)
#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include 
using namespace std;
const int mod = 1e9+7;
const int N = 1e6 + 10;
int dp[N][2];//代表第i位是0或1的个数
int n, k;
signed main(void) {
	
	cin >> n >> k;
	dp[0][0] = 1;
	//dp[0][1] = 1;
	for (int i = 1; i <= n; ++i) {
		dp[i][0] = (dp[i - 1][0] + dp[i - 1][1]) % mod;
		dp[i][1] = (dp[i - k - 1 > 0 ? i-k-1 : 0][0] + dp[i - k - 1 > 0 ? i-k-1 : 0][1]) % mod;
	}
	cout << (dp[n][0] + dp[n][1]) % mod;
	
	return 0;
}

假设第i位要填0,则前一位是0或1都没有什么影响

假设第i位要填1,则至少第i-k位到第i-1位都要是0,但是如果第i-k-1位是0就没有影响了

所以 d p [ i ] [ 1 ] = d p [ i − k − 1 ] [ 0 ] + d p [ i − k − 1 ] [ 1 ] dp[i][1]=dp[i-k-1][0]+dp[i-k-1][1] dp[i][1]=dp[ik1][0]+dp[ik1][1] 为什么啊,因为后面这几位都要是0

初始状态设 d p [ 0 ] [ 0 ] = 1 dp[0][0]=1 dp[0][0]=1 (为什么啊,为什么 d p [ 0 ] [ 1 ] dp[0][1] dp[0][1]不也设成1,举个例子就知道了)

然后考虑当i-k-1小于0时,就默认从 d p [ 0 ] [ 0 ] dp[0][0] dp[0][0]转移过来 why???

601 bfs练习
#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include 
#include 
#include 
using namespace std;
queue<int>q;
const int mod = 1e9+7;
const int N = 1e6 + 10;
int dis[N];
int ch[N];
void bfs(int v, int u) {
	if (v >= 1 && v <= 1e5 && dis[v] == 0x3f3f3f3f) {
		dis[v] = dis[u] + 1;
		q.push(v);
	}
}
signed main(void) {
	int a, x;
	cin >> a >> x;
	memset(dis, 0x3f, sizeof(dis));
	dis[a] = 0;
	for (int i = 1; i <= x; ++i) cin >> ch[i];
	q.push(a);
	while (!q.empty()) {
		int u = q.front();
		bfs(u+1, u);
		bfs(u * 2, u);
		bfs(u * 3, u);
		bfs(u - 1, u);
		q.pop();
	}
	for (int i = 1; i <= x; ++i) {
		cout << dis[ch[i]] << " ";
	}
	return 0;
}

初始值设为最大值用来判断这个数字有没有出现过,如果出现过就没必要继续进行操作了,因为在这之前出现的数的dis肯定更小

第二次自己做:

#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include 
#include 
#include 
using namespace std;
const int N = 2e6 + 10;
int ch[N];
int vis[N], ans[N];
queue<int>x;
map<int, int>mp;
int main(void) {
	int a, q;
	cin >> a >> q;
	for (int i = 1; i <= q; ++i) {
		scanf("%d", &ch[i]);
		mp[ch[i]] = 1;
	}
	int cnt = 0;
	x.push(a);
	vis[a] = 1;
	ans[a] = 0;
	if (mp[a] == 1) cnt++;
	while (!x.empty()) {
		int n = x.front();
		x.pop();
		if (n > 1e5) continue;
		if (n + 1 <= 1e5) {
			if (vis[n + 1] == 0) {
				x.push(n + 1);
				ans[n + 1] = ans[n] + 1;
				vis[n + 1] = 1;
				if (mp[n + 1] == 1) cnt++;
			}
		}
		if (n * 2 <= 1e5) {
			if (vis[n * 2] == 0) {
				x.push(n * 2);
				ans[n * 2] = ans[n] + 1;
				vis[n * 2] = 1;
				if (mp[n * 2] == 1) cnt++;
			}
		}
		if (n * 3 <= 1e5) {
			if (vis[n * 3] == 0) {
				x.push(n * 3);
				ans[n * 3] = ans[n] + 1;
				vis[n * 3] = 1;
				if (mp[n * 3] == 1) cnt++;
			}
		}
		if (n - 1 <= 1e5&&n-1>=0) {//不特判会RE
			if (vis[n - 1] == 0) {
				x.push(n - 1);
				ans[n - 1] = ans[n] + 1;
				vis[n - 1] = 1;
				if (mp[n - 1] == 1) cnt++;
			}
		}
		if (cnt >= q) break;//如果都出现过了就break呗,但是为什么比上面的要慢啊
	}
	for (int i = 1; i <= q; ++i) {
		printf("%d ", ans[ch[i]]);
	}
	return 0;
}
整除光棍
#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include 
#include 
#include 
using namespace std;
signed main(void) {
	int x;
	cin >> x;
	int i = 1;
	int ans = 1;
	int first = 1;
	if (x == 1) {
		cout << 1 << " " << 1;
		return 0;
	}
	while (1) {
		if (i % x != 0) {
			i = (i % x) * 10 + 1;
			ans++;
			if (i / x == 0) {
				if (!first) cout << 0;
			}
			else {
				cout << i / x;
				first = 0;//不能输出前导0
			}
		}
		else break;
	}
	cout << " " << ans;
	
	return 0;
}

思想就是不断增加1 的个数,判断是否满足条件。高精度的题,类似于除法竖式,再后面补1

507 Luris的游戏
#include 
using namespace std;
const int N = 1e5 + 10;
int ch[N],n;
int check(int mid) {
	int init = mid;
	for (int i = 1; i <= n; ++i) {
		if (ch[i] > init) init = init - (ch[i] - init);
		else init = init + (init - ch[i]);
		if (init < 0) return 0;
		if (init > 1e5+10) return 1;//不加这一句就错了啊,因为会爆longlong
	}
	return 1;
}
int main(void) {
	int maxx=0;
	cin >> n;
	for (int i = 1; i <= n; ++i) {
		cin >> ch[i];
		if (ch[i] > maxx) maxx = ch[i];
	}
	int l = 1, r = maxx + 1;
	while (l < r) {
		int mid = (l + r) / 2;
		//cout <
		if (check(mid)==1) r = mid;
		else l = mid + 1;
	}
	cout << l;
	return 0;
}
506 完美数
#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
int ch[N];
ll fact[N], infact[N];
int a, b, m;
const int mod = 1e9 + 7;
int check(int x) {
	while (x > 0) {
		if (x % 10 == a || x % 10 == b) x = x / 10;
		else return 0;
	}
	return 1;
}
ll qpow(ll base, ll pow) {//快速幂 
	ll ans = 1;
	while (pow) {
		if (pow & 1) ans = ans * base % mod;
		base = base * base % mod;
		pow >>= 1;
	}
	return ans;
}
void init() {
	fact[0] = infact[0] = 1;
	for (int i = 1; i < N; i++) {
		//阶乘预处理,打表
		fact[i] = fact[i - 1] * i % mod;
		//逆元 i 的 mod-2次方就是 i的模 mod的逆元
		infact[i] = infact[i - 1] * qpow(i, mod - 2) % mod;
	}
}
ll c(int n, int k) {
	if (k<0 || k>n) return 0;
	return fact[n] * infact[k] % mod * infact[n - k] % mod;
}

signed main(void) {
	init();
	cin >> a >> b >> m;
	int ans = 0,cnt=0;
	if (a > b) swap(a, b);
	for (int i = 1; i <= m+1; ++i) {
		ch[i] = (b - a) * (i-1) + a*m;
		if (check(ch[i])) {
			cnt++;
			ans = (ans + c(m, i-1) ) % mod;
		}
	}
	cout << ans;
	/*cout << cnt;
	cout << "\n";
	cout << c(6,5)<<"\n"<
	return 0;
}

枚举总和,如果满足条件,求组合数(求组合数的板子)

407 饿饿饭饭暑假狂欢
#include 
using namespace std;
int ch[200][200];
int kk[200];
int flag[200];
int main(void) {
	int n, k, x;
	cin >> n;
	for (int i = 1; i <= n; ++i) {
		cin >> kk[i];
		for (int j = 1; j <= kk[i]; ++j) {
			cin >> ch[i][j];
		}
	}
	for (int i = 1; i <= n; ++i) {
		for (int j =  1; j <= n; ++j) { //还是要从1开始,不能从i+1开始
			if (j == i) continue;
			int sum = 0;
			for (int k = 1; k <= kk[i]; ++k) {
				for (int l = 1; l <= kk[j]; ++l)    {
					if (ch[i][k] == ch[j][l]) {
						sum++;
						break;//要break,因为有重复的,这时继续加就会出错
					}
				}
			}
			if (sum == kk[i]) flag[j] = 1;
		}
	}
	for (int i = 1; i <= n; ++i) {
		if (flag[i]) cout << "NO\n";
		else cout << "YES\n";
	}
	return 0;
}

模拟题,就按题目意思写就行,还是有所收获的,就比如for循环的顺序,范围

406 循环子串
#include 
#include 
#include 
using namespace std;
string s[109];
int len[109];
int main(void) {
	int n;
	cin >> n;
	for (int i = 1; i <= n; ++i) {
		cin >> len[i];
		cin >> s[i];
	}
	for (int i = 1; i <= n; ++i) {
		string sssss = s[i];
		//string str = s.reserve();这种写法根本没翻转
		reverse(sssss.begin(), sssss.end());
		//cout << sssss << "\n";
		int flag = 0;
		for (int j = 0; j < len[i]; ++j) {
			//cout << s[i].substr(len[i] - j) << " " << s[i].substr(0, len[i] - j) << "\n";
			if((s[i].substr(len[i] - j)+s[i].substr(0,len[i]-j))==sssss) flag=1;
		}
		if(flag) cout<<"YES\n";
		else cout<<"NO\n";
	}
	return 0;
}

首先要转化一下的,子串翻转后要成为循环子串,那么只要满足原串翻转后与循环相等即可

然后学到了字符串翻转的写法

604 碰撞2
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int N = 2e5 + 10;
map<int, int>mpl;//记录第i行往左走的最大值
map<int, int>mpr;//记录第i行往右走的最小值
struct node {
	int x;
	int y;
}point[N];
//找每一行中往左走的最大值,和往右走的最小值,如果maxx>min,就会产生碰撞
int main(void) {
	int n;
	string str;
	cin >> n;
	for (int i = 0; i < n; ++i) {
		cin >> point[i].x >> point[i].y;
		mpl[point[i].y] = -1;
		mpr[point[i].y] = 1e9;
	}
	cin >> str;
	for (int i = 0; i < n; ++i) {
		if (str[i] == 'L') {
			mpl[point[i].y] = max(point[i].x, mpl[point[i].y]);
			if (mpr[point[i].y] < point[i].x) {
				cout << "Yes";
				return 0;
			}
		}
		if (str[i] == 'R') {
			mpr[point[i].y] = min(point[i].x, mpr[point[i].y]);
			if (mpl[point[i].y] > point[i].x) {
				cout << "Yes";
				return 0;
			}
		}
	}
	cout << "No";
	return 0;
}

如果某一时刻满足条件就可以直接输出return了

还有一种做法,就是读取完后再进行操作

#include 
#include 
#include 
#include 
#include 
using namespace std;
const int N = 2e5 + 10;
map<int, int>mpl;//记录第i行往左走的最大值
map<int, int>mpr;//记录第i行往右走的最小值
struct node {
	int x;
	int y;
}point[N];
//找每一行中往左走的最大值,和往右走的最小值,如果maxx>min,就会产生碰撞
int main(void) {
	int n;
	string str;
	cin >> n;
	for (int i = 0; i < n; ++i) {
		cin >> point[i].x >> point[i].y;
		mpl[point[i].y] = -1;
		mpr[point[i].y] = 1e9;
	}
	cin >> str;
	for (int i = 0; i < n; ++i) {
		if (str[i] == 'L') mpl[point[i].y] = max(mpl[point[i].y], point[i].x);
		else mpr[point[i].y] = min(mpr[point[i].y], point[i].x);
	}
	/*for (auto t : mpl) {
		cout << t.first << " " << t.second<<" ";
	}
	cout << "\n";
	for (auto t : mpr) {
		cout << t.first << " " << t.second<<" ";
	}*/
	for (auto t : mpr) {
		if (t.second == 1e9) continue;
		if (t.second < mpl[t.first]) {
			cout << "Yes";
			return 0;
		}
	}
	cout << "No";
	return 0;
}

建议以后使用map循环时,先输出答案看看,这里就发现他是从0开始的,直到有出现的最大的,就是说没有出现的也会在for循环里面

606巨大的牛棚

动态规划做法:要理解转移方程,挺难的

#include 
#include 
#include 
#include 
#include 
using namespace std;
const int N = 2e3 + 10;
int ch[N][N];
int dp[N][N];
int main(void) {
	int n, t;
	int x, y;
	cin >> n >> t;
	for (int i = 1; i <= t; ++i) {
		cin >> x >> y;
		ch[x][y] = 1;
	}
	int maxx = 0;
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= n; ++j) {
			if (ch[i][j] == 0) {
				dp[i][j] = min(dp[i - 1][j], min(dp[i][j - 1], dp[i - 1][j - 1]))+1;
				if (dp[i][j] > maxx) maxx = dp[i][j];
			}
		}
	}
	cout << maxx;
	return 0;
}

类似题目

洛谷1387最大正方形

输入一个矩阵,有0有1

找到为1的最大正方形

解法:前缀和+暴力枚举边长

优化:从大到小枚举

#include 
#include 
#include 
#include 
#include 
using namespace std;
const int N = 2e3 + 10;
int ch[N][N];
int cnt[N][N];
int main(void) {
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j) {
			cin >> ch[i][j];
			cnt[i][j] = cnt[i - 1][j] + cnt[i][j - 1] - cnt[i - 1][j - 1] + ch[i][j];//前缀和
		}
	}
	int ans = 1;
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j) {
			for (int k = ans; k <= min(n, m); ++k) {//为什么这里是从小到大枚举,而下面的暴力是从大到小枚举,因为如果这里从大到小枚举的话,最大的满足不了,跳出循环,就找下一个点去了,而下面暴力解法的跳出循环是跳到k-1
				if (i + k > n || j + k > m || (cnt[i + k][j + k]-cnt[i-1][j+k]-cnt[i+k][j-1]+cnt[i-1][j-1] != ((k+1)*(k+1)))) break;
				ans = max(ans, k+1);
			}
		}
	}
	cout << ans;
	return 0;
}









#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include 
using namespace std;
int ch[101][101];
int cnt[1010][1010];
int main(void) {
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j) {
			scanf("%d", &ch[i][j]);
			cnt[i][j] = cnt[i - 1][j] + cnt[i][j - 1] - cnt[i - 1][j - 1] + ch[i][j];
		}
	}
	int ans = 1;
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j) {
			for (int k = min(n,m); k >=ans; --k) {
				if (i + k > n || j + k > m) continue;//如果从大到小枚举的话,应该是相等跳出循环
				if (i + k <= n&& j + k <= m && (cnt[i + k][j + k] - cnt[i - 1][j + k] - cnt[i + k][j - 1] + cnt[i - 1][j - 1]) == ((k + 1) * (k + 1))) {
					ans = k + 1;
					break;
				}
			}
		}
	}
	cout << ans;
	return 0;
}

暴力解法

#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include 
using namespace std;
int ch[101][101];
int main(void) {
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j) {
			scanf("%d", &ch[i][j]);
		}
	}
	int ans = 1;
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j) {
			for (int k = min(n, m); k >= ans; --k) {
				int p = 0;
				for (int x = i; x < i + k; ++x) {
					for (int y = j; y < j + k; ++y) {
						if (x>n||y>m||ch[x][y] == 0) p = 1;
						if (p == 1) break;
					}
					if (p == 1) break;
				}
				if (p == 0) ans = k;
			}
		}
	}
	cout << ans;
	return 0;
}
607 高利贷
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int N = 2e3 + 10;
int ch[N][N];
int cnt[N][N];
const double eps = 1e-8;
int n, m, k;
double check(double mid) {
	double sum = 0;
	for (int i = 1; i <= k; ++i) {
		sum = sum + m / pow(1 + mid, i);
	}
	if (sum >= n) return 1;
	return 0;
}
int main(void) {
	cin >> n >> m >> k;
	double l = 0, r = 5;
	for (int i = 1; i <= 100; ++i) {
		double mid = (l + r) / 2;
		if (check(mid)) l= mid;
		else r = mid;
	}
	//cout << l;
	printf("%.6f", l);//卡精度的题看来得用printf卡小数点位数,反正我cout过不了
	return 0;
}
701 背包
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define int long long
const int N = 2e5 + 10;
int ch[N];
int n, m, k;
signed main(void) {
	int t, n, w;
	int check;
	cin >> t;
	while (t--) {
		cin >> n >> w;
		if (w % 2 == 0) check = w / 2;
		else check = (w + 1) / 2;
		int flag = 0;
		for (int i = 1; i <= n; ++i) {
			cin >> ch[i];
			if (ch[i] >= check && ch[i] <= w) flag = 1;
		}
		if (flag) {
			cout << "YES" << "\n";
			continue;
		}
		sort(ch + 1, ch + 1 + n);
		int sum = 0;
        //for循环从前往后,或者从后往前都可以
		for (int i = n; i >=1; --i) {
			sum += ch[i];
			if (sum > w) sum -= ch[i];
			else if (sum >= check) {
				flag = 1;
				break;
			}
		}
		if (flag) cout << "YES\n";
		else cout << "NO" << "\n";
	}
	return 0;
}

这里要搞清楚的是肯定是连续的,而不是间断的,即不存在123超过w但是13满足的情况,因为如果说123超了,就说明12肯定满足了,因为这时的每个物品的体积都小于w/2(因为如果有一个物品体积>w/2&&

703 简单的异或问题
#include 
#include 
using namespace std;
#define int long long
signed main(void) {
	int n, m;
	cin >> n >> m;
	if (m == 1) {
		if (n == 1) {
			cout << 2;
			return 0;
		}
		else {
			cout << 1;
			return 0;
		}
	}
	int ans = pow(2, m);//直接cout<
	if (n == 0) cout << ans;
	else cout << ans - 1;
	return 0;
}

有一个结论就是,从0到 2 n − 1 2^n-1 2n1的异或和是0(在n不为1时) ,然后假如你要得到x,只要异或和时不取x即可。

m 异或 x = 0 m异或x=0 m异或x=0 则m=x

为什么想到这个呢,因为题目要求最多,所以要想到全部都选是什么情况,还有就是这个数给的挺特殊,关于2的几次方

605优美!最长上升子序列
#include 
#include 
#include 
using namespace std;
const int N = 1e6 + 10;
int dp[N];
int ch[N];
int main(void) {
	int t, n;
	cin >> t;
	while (t--) {
		cin >> n;
		memset(ch, 0, sizeof(ch));
		memset(dp, 0, sizeof(dp));
		int maxx = 0;
		for (int i = 1; i <= n; ++i) cin >> ch[i];
		for (int i = 1; i <= n; ++i) {
			maxx = max(dp[i], maxx);
			for (int j = i + i; j <= n; j = j + i) {
				if (ch[j] > ch[i]) dp[j] = max(dp[j], dp[i] + 1);
			}
		}
		cout << maxx + 1 << "\n";
	}
	return 0;
}

与往常的dp不太一样,求最长上升子序列是枚举i,for int j=1;j

706上帝的集合 (好题)

#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define int long long
priority_queue<int, vector<int>,greater<int> >q;//定义的方法我忘了寄
//还有一种方法就是还是大根堆,但是push的时候把他变成负数是不是就可以了,这里应该不太行,因为后面涉及到加减法相关的操作
signed main(void) {
	int n;
	int x,y;
	int tag = 0;
	scanf("%lld",&n);
	while (n--) {
		scanf("%lld", &x);
		if (x == 1) {
			scanf("%lld", &y);
			q.push(y - tag);//保持相对的大小关系!!!!!!!!
		}
		else if (x == 2) {
			scanf("%lld", &y);
			tag += y;
		}
		else {
			int u = q.top();
			q.pop();
			printf("%lld\n", u + tag);
		}
	}
	return 0;
}
定义大根堆的方法需要记一下的,还有就是全部元素加上一个数,如果循环逐个加的话肯定会炸,所以定义一个tag来存储现在加了多少,但是新插入一个数时push的时候要减去当前的tag,输出的时候要加上tag
    还有就是#define int long long 然后scanf里面要用lld别忘了
704 子串的循环挪动
#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include 
#include 
#include 
#include 
using namespace std;
signed main(void) {
	int n;
	int l, r, k;
	string str;
	cin >> str;
	cin >> n;
	for (int i = 1; i <= n; ++i) {
		cin >> l >> r >> k;
		k = k % (r - l + 1);
		if (k == 0) continue;
		str = str.substr(0, l - 1) + str.substr(r - k, k) + str.substr(l - 1, r-l + 1 - k) + str.substr(r);
		}
		cout << str;

	return 0;
}

简单的模拟题

挖地雷

在一个地图上有N个地窖(N<=20),每个地窖中埋有一定数量的地雷。同时,给出地窖之间的连接路径。

当地窖及其连接的数据给出之后,某人可以从任一处开始挖地雷,然后可以沿着指出的连接往下挖(仅能选择一条路径),当无连接时挖地雷工作结束。设计一个挖地雷的方案,使某人能挖到最多的地雷。

W1 W2 W3 …… WN(表示每个地窖中埋藏的地雷数量)

A12…………… . A1N(地窖之间连接路径,其中Aij=1表示地窖i,j之间是否有通路:通Aij=1,不通Aij==0)

A23……………A2N

……… AN-1 N

#include 
using namespace std;
#define int long long 
int a[101];
bool check[111];
int n;
int maxx;
bool f[111][111];
bool chck(int x)
{
	for (int i = 1; i <= n; i++)
	{
		if (f[x][i] && !check[i]) return false;
	}
	return true;
}
void dfs(int x, int sum)
{
	if (chck(x))
	{
		if (maxx < sum)
		{
			maxx = sum;
		}
		return;
	}
	for (int i = 1; i <= n; i++)
	{
		if (f[x][i] && !check[i])
		{
			check[i] = 1;
			dfs(i, sum + a[i]);
			check[i] = 0;//别忘了回溯。。。。。
		}
	}
}
signed main()
{
	cin >> n;
	for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
	for (int i = 1; i < n; i++)
	{
		for (int j = i + 1; j <= n; ++j) {
			scanf("%lld", &f[i][j]);
			f[j][i] = f[i][j];//双向边
		}
	}
	for (int i = 1; i <= n; i++)
	{
		check[i] = 1;
		dfs(i, a[i]);
		check[i] = 0;
	}
	cout << maxx;
	return 0;
}

你可能感兴趣的:(算法入门,算法,图论,动态规划)