方法技巧:
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;
}
李白打酒: