dfs+剪枝
#include
#define ll long long
#define INF 0x7f7f7f7f
using namespace std;
const int N=3e8+10;
int n,m,ans,k;
int a[110],vis[N];
bool check(int date) {
if(vis[date])return false;
vis[date]=1;
int mm=date/100%100;
int dd=date%100;
if(mm<1||mm>12)return false;
if(mm==1||mm==3||mm==5||mm==7||mm==8||mm==10||mm==12) {
if(dd>=1&&dd<=31)return true;
} else if(mm==2) {
if(dd>=1&&dd<=28)return true;
} else if(dd>=1&&dd<=30)return true;
return false;
}
void dfs(int x,int cnt,int date) { //传入当前位置,第几位,日期
if(x==100)return ;
if(cnt==8) {
if(check(date))ans++;
return ;
}
if((cnt==0&&a[x]==2)||(cnt==1&&a[x]==0)||(cnt==2&&a[x]==2)||(cnt==3&&a[x]==3)||(cnt==4&&a[x]>=0&&a[x]<=1)||(cnt==5&&a[x]>=0&&a[x]<=9)||(cnt==6&&a[x]>=0&&a[x]<=3)||(cnt==7&a[x]>=0&&a[x]<=9))
dfs(x+1,cnt+1,date*10+a[x]);//合法可以选
dfs(x+1,cnt,date);//不选
}
int main() {
/*
5 6 8 6 9 1 6 1 2 4 9 1 9 8 2 3 6 4 7 7 5 9 5 0 3 8 7 5 8 1 5 8 6 1 8 3 0 3 7 9 2
7 0 5 8 8 5 7 0 9 9 1 9 4 4 6 8 6 3 3 8 5 1 6 3 4 6 7 0 7 8 2 7 6 8 9 5 6 5 6 1 4 0 1
0 0 9 4 8 0 9 1 2 8 5 0 2 5 3 3
*/
for(int i=0; i<100; i++)cin>>a[i];
dfs(0,0,0);
cout<<ans;
return 0;
}
答案:235
考察枚举,遇见这种式子不要慌,慢慢分析推导
注意浮点数的处理方式每次用1.0乘上一个int数转为浮点数
注意log函数的使用
注意结果的判断方式
#include
#define ll long long
#define INF 0x7f7f7f7f
using namespace std;
const int N=23333333;
int n,m,k;
double ans=11625907.5798,esp=1e-4;
int main() {
for(int m=0;m<=N/2;m++){//枚举0的个数
n=N-m;//1的个数
double res=-1.0*m*m/N*log2(1.0*m/N)-1.0*n*n/N*log2(1.0*n/N);
if(fabs(res-ans)<esp){
cout<<m<<endl;
return 0;
}
}
return 0;
}
二分转换率
#include
#define ll long long
#define INF 0x7f7f7f7f
using namespace std;
const int N=1e4+10;
int n,m,k,ans;
int a[N],b[N];
bool check_min(int v) {
for(int i=1; i<=n; i++) {
if(a[i]/v>b[i])return false;
}
return true;
}
bool check_max(int v) {
for(int i=1; i<=n; i++) {
if(a[i]/v<b[i])return false;
}
return true;
}
int main() {
cin>>n;
for(int i=1; i<=n; i++)cin>>a[i]>>b[i];
int l=0,r=1e9;
while(l<r) {
int mid=l+r>>1;
if(check_min(mid)) {
r=mid;
} else {
l=mid+1;
}
}
cout<<r<<" ";
l=0,r=1e9;
while(l<r){
int mid=l+r+1>>1;
if(check_max(mid))l=mid;
else r=mid-1;
}
cout<<r<<endl;
return 0;
}
全排列
#include
#define ll long long
#define INF 0x7f7f7f7f
using namespace std;
const int N=20;
int n,m,k,ans;
bool flag;
int T[N],D[N],L[N];
int vis[N];
void dfs(int k,int t) { //已经放了k架飞机,当前时间为t
if(k==n) {
flag=true;
return ;
}
for(int i=1; i<=n; i++) {
if(!vis[i]) {
if(T[i]+D[i]>=t) {
vis[i]=1;
dfs(k+1,max(t+L[i],T[i]+L[i]));//注意这里要取最大,因为飞机可能没有到达
vis[i]=0;
}
}
}
}
int main() {
int t;
cin>>t;
while(t--) {
memset(vis,0,sizeof(vis));
flag=false;
cin>>n;
for(int i=1; i<=n; i++) {
cin>>T[i]>>D[i]>>L[i];
}
for(int i=1; i<=n; i++) {
if(!vis[i]) {
vis[i]=1;
dfs(1,T[i]+L[i]);
vis[i]=0;
}
}
if(flag)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
dp
#include
#define ll long long
using namespace std;
typedef pair<int,int> PII;
const int N=1e5+10;
int n,m,ans;
int f[N][10];
int a[N];
int fun(int x) {
while(x/10) x/=10;
return x;
}
int main() {
/*
5
11 121 22 12 2023
*/
cin>>n;
for(int i=1; i<=n; i++)cin>>a[i];
for(int i=1; i<=n; i++) {
for(int j=0; j<=9; j++) {
f[i][j]=f[i-1][j];//先继承
}
f[i][a[i]%10]=max(f[i][a[i]%10],f[i-1][fun(a[i])]+1);//要么是继承的结果大,要么是把他加入新的序列结果大
}
ans=-1;
for(int i=0; i<=9; i++) {
ans=max(f[n][i],ans);
}
cout<<n-ans;
return 0;
}
bfs染色问题
首先遍历每一个点从每一个点出发如果该点为陆地那么进行染色,把上下左右相邻的陆地全部染色
在进行判断,从该点出入,一直在海里游向八个方向游泳,如果能够游到边界,那么该点和该点染色的陆地形成独立的岛屿,如果游不出去,那么该点和延申的岛屿均为子岛
#include
#define ll long long
#define INF 0x7f7f7f7f
using namespace std;
const int N=60;
int n,m,k,ans;
int dx[8]= {1,0,-1,0,1,-1,-1,1}; //上右下左,右上、右下、左下、左上
int dy[8]= {0,1,0,-1,1,1,-1,-1};
int vis[N][N];
int used[N][N];
string M[N];//必须用string int读入必须有空格
void bfs_col(int x,int y) {
queue<int>qx,qy;
qx.push(x);
qy.push(y);
while(!qx.empty()) {
x=qx.front(),y=qy.front();
qx.pop(),qy.pop();
//上右下左四个方向bfs
for(int i=0; i<4; i++) {
int nx=x+dx[i];
int ny=y+dy[i];
if(nx<0 || nx>=n || ny<0 || ny>=m || vis[nx][ny] || M[nx][ny]=='0') continue;//不合法
qx.push(nx);
qy.push(ny);
vis[nx][ny]=1;
}
}
}
bool bfs_out(int x,int y) {
memset(used,0,sizeof(used));
queue<int>qx,qy;
qx.push(x);
qy.push(y);
used[x][y]=1;
while(!qx.empty()) {
x=qx.front();
qx.pop();
y=qy.front();
qy.pop();
if(x==0 || x==n-1 || y==0 || y==m-1) return true;;//走到边界证明该岛屿为单个岛
for(int i=0; i<8; i++) {
int nx=x+dx[i];
int ny=y+dy[i];
if(nx<0 || nx>=n || ny<0 || ny>=m || used[nx][ny] || M[nx][ny]=='1') continue;
qx.push(nx);
qy.push(ny);
used[nx][ny]=1;
}
}
return false;
}
int main() {
int T;
cin>>T;
while(T--) {
memset(vis,0,sizeof(vis));
cin>>n>>m;//n行m列
for(int i=0; i<n; i++)
cin>>M[i];
ans=0;
for(int i=0; i<n; i++) {
for(int j=0; j<m; j++) {
if(!vis[i][j]&&M[i][j]=='1') {
vis[i][j]=1;
bfs_col(i,j);//把所有上下左右相邻的1染色
if(bfs_out(i,j))ans++;
}
}
}
cout<<ans<<endl;
}
return 0;
}
双指针+前缀和
以当前点位右端点,向左想(不要总是从左向右想)
#include
#define ll long long
#define INF 0x7f7f7f7f
using namespace std;
const int N=60;
ll n,m,k,ans;
int main() {
cin>>k;
string str;
cin>>str;
char c1,c2;
cin>>c1>>c2;
n=str.size();
ll sum=0;
//i和j保持k的距离
for(int i=k-1,j=0; i<n; i++,j++) { //双指针+前缀和
if(str[j]==c1) sum++;
if(str[i]==c2) ans+=sum;//碰到一个c2就开始收割
}
cout<<ans<<endl;
return 0;
}
优先队列+链表
#include
#define ll long long
#define INF 0x7f7f7f7f
using namespace std;
typedef pair<ll,int> PII;
const int N=5e5+10;
int n,m,k,ans;
ll pre[N],nex[N];v[N];
priority_queue<PII,vector<PII>,greater<PII> > q;
void del(int x) {
nex[pre[x]]=nex[x];
pre[nex[x]]=pre[x];
v[pre[x]]+=v[x],v[nex[x]]+=v[x];
}
int main() {
cin>>n>>k;
pre[n+1]=n,nex[0]=1;//初始化双向链表
//创建链表
for(int i=1; i<=n; i++) {
cin>>v[i];
pre[i]=i-1;
nex[i]=i+1;
q.push({v[i],i});
}
while(k--) {
PII p=q.top();
q.pop();
if(p.first!=v[p.second])q.push({v[p.second],p.second}),k++;//更新重新放入堆
else del(p.second);
}
int p=nex[0];
while(p!=n+1) {
cout<<v[p]<<" ";
p=nex[p];
}
return 0;
}
LCA应用求树上两点间距离
#include
#define ll long long
#define INF 0x7f7f7f7f
using namespace std;
typedef pair<ll,int> PII;
const int N=1e5+10;
int n,m,ecnt;
int f[N][30];
int d[N],head[N];
int A[N];
ll sum[N];
struct edge {
int u,v,w,next;
} E[N<<1];
void add(int u,int v,int w) {
E[++ecnt].u=u;
E[ecnt].v=v;
E[ecnt].w=w;
E[ecnt].next=head[u];
head[u]=ecnt;
}
void dfs(int u,int fa) {
d[u]=d[fa]+1;
f[u][0]=fa;
for(int i=1; i<=20; i++)
f[u][i]=f[f[u][i-1]][i-1];
for(int i=head[u]; i; i=E[i].next) {
int v=E[i].v;
if(fa!=v) {
sum[v]=sum[u]+E[i].w;
dfs(v,u);
}
}
}
int LCA(int x,int y) {
if(d[x]<d[y])swap(x,y);
for(int i=20; i>=0; i--) {
if(d[f[x][i]]>=d[y])x=f[x][i];
}
if(x==y)return x;
for(int i=20; i>=0; i--) {
if(f[x][i]!=f[y][i]) {
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
ll path_dis(int x,int y) {
if(x==0||y==0)return 0;
return sum[x]+sum[y]-2*sum[LCA(x,y)];
}
int main() {
cin>>n>>m;
for(int i=1; i<n; i++) {
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);
add(v,u,w);
}
dfs(1,0);
ll ans=0;
for(int i=1; i<=m; i++) {
cin>>A[i];
ans+=path_dis(A[i],A[i-1]);
}
//减去前一段,前去后一段,加上新的一段
for(int i=1; i<=m; i++) {
cout<<ans-path_dis(A[i],A[i-1])-path_dis(A[i],A[i+1])+path_dis(A[i-1],A[i+1])<<" ";
}
return 0;
}
树上差分
#include
#define ll long long
#define INF 0x7f7f7f7f
using namespace std;
typedef pair<ll,int> PII;
const int N=1e5+10;
int n,m,ecnt,ans;
int f[N][30];
int d[N],head[N];
int cnt[N];
struct edge{
int u,v,next;
} E[N<<1];
void add(int u,int v) {
E[++ecnt].u=u;
E[ecnt].v=v;
E[ecnt].next=head[u];
head[u]=ecnt;
}
void dfs(int u,int fa) {
d[u]=d[fa]+1;
f[u][0]=fa;
for(int i=1; i<=20; i++)
f[u][i]=f[f[u][i-1]][i-1];
for(int i=head[u]; i; i=E[i].next) {
int v=E[i].v;
if(v==fa)continue;
dfs(v,u);
}
}
int lca(int x,int y) {
if(d[x]<d[y])swap(x,y);
for(int i=20; i>=0; i--) {
if(d[f[x][i]]>=d[y])x=f[x][i];
}
if(x==y)return x;
for(int i=20; i>=0; i--) {
if(f[x][i]!=f[y][i]) {
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
void dfs2(int u,int fa) {
for(int i=head[u]; i; i=E[i].next) {
int v=E[i].v;
if(v==fa)continue;
dfs2(v,u);
cnt[u]+=cnt[v];//树上差分
if(cnt[v]==m)ans=max(ans,i);//所有不同点,的公共路径
}
}
int main() {
cin>>n>>m;
for(int i=1; i<n; i++) {
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
dfs(1,0);
for(int i=1; i<=m; i++) {
int a,b;
cin>>a>>b;
cnt[a]++,cnt[b]++,cnt[lca(a,b)]-=2;
}
dfs2(1,0);
cout<<(ans+1)/2<<endl;//每次建立双向边所以要除以2
return 0;
}