Summer training #9
A:树形DP
给出一棵树,但是它的边是有向边,选择一个城市,问最少调整多少条边的方向能使一个选中城市可以到达所有的点,输出最小的调整的边数,和对应的点
要改变的边的权值为1,不需要改变的边的权值为0,
两次dfs 第一次算出以1点为根节点到所有点要改变的边数,第二次以1为根节点向下遍历节点 算出每一个点到达所有点要改变的边数,
dp[son]+=(dp[root]-dp[son])+((tree[i].val)?-1:1),某一点的值是他父节点的值减去他以前的值再考虑他与父节点之间的边的方向。
#include<iostream> #include<string> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<vector> #include<iomanip> #include<queue> #include<stack> using namespace std; int n,lne; int dp[200010]; int head[200010]; int city[200010]; struct node { int to,next,val; }tree[400010]; void add(int a,int b) { tree[lne].to=b; tree[lne].val=0; tree[lne].next=head[a]; head[a]=lne++; tree[lne].to=a; tree[lne].val=1; tree[lne].next=head[b]; head[b]=lne++; } void dfs1(int root,int pre) { for(int i=head[root];i!=-1;i=tree[i].next) { int son=tree[i].to; if(son==pre) continue; dfs1(son,root); dp[root]+=dp[son]+tree[i].val; } } void dfs2(int root,int pre) { for(int i=head[root];i!=-1;i=tree[i].next) { int son=tree[i].to; if(son==pre) continue; dp[son]+=(dp[root]-dp[son])+((tree[i].val)?-1:1); dfs2(son,root); } } int main() { int a,b; while(scanf("%d",&n)!=EOF) { lne=0; memset(head,-1,sizeof(head)); for(int i=0;i<n-1;i++) { scanf("%d%d",&a,&b); add(a,b); } int k=0,sum=10000000; memset(dp,0,sizeof(dp)); dfs1(1,0); dfs2(1,0); for(int i=1;i<=n;i++) { if(dp[i]<sum) { memset(city,0,sizeof(city)); k=0; city[k++]=i; sum=dp[i]; } else if(dp[i]==sum) city[k++]=i; } printf("%d\n",sum); for(int i=0;i<k;i++) { if(i==k-1) printf("%d\n",city[i]); else printf("%d ",city[i]); } } return 0; }
B:算表面积 先把每个除了四周都加起来 然后减去四周重复的
#include <bits/stdc++.h> #include <cstring> #include <iostream> #include <algorithm> #define foror(i,a,b) for(i=a;i<b;i++) #define foror2(i,a,b) for(i=a;i>b;i--) #define EPS 1.0e-6 #define PI acos(-1.0) #define INF 3000000000 #define MOD 1000000009 #define mem(a,b) memset((a),b,sizeof(a)) #define TS printf("!!!\n") #define lson o<<1, l, m #define rson o<<1|1, m+1, r //using ll = long long; //using ull= unsigned long long; //std::ios::sync_with_stdio(false); using namespace std; //priority_queue<int,vector<int>,greater<int>> que; typedef long long ll; int a[110][110]; char s[110][110]; int dir[4][2]; int main() { freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); dir[0][0]=-1,dir[0][1]=0; dir[1][0]=1,dir[1][1]=0; dir[2][0]=0,dir[2][1]=1; dir[3][0]=0,dir[3][1]=-1; int n,m ; cin >> n >> m; mem(a,0); for(int i=1;i<=n;i++) { scanf("%s",s[i]+1); for(int j=1;j<=m;j++) a[i][j]=s[i][j]-'0'; } int ans=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { ans+=a[i][j]*4+2; if(a[i][j]==0) ans-=2; } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { for(int w=0;w<4;w++) { int dx=i+dir[w][0]; int dy=j+dir[w][1]; ans-=min(a[i][j],a[dx][dy]); } } cout<<ans<<endl; return 0; }
C:DFS+二进制压缩
#include <bits/stdc++.h> #include <cstring> #include <iostream> #include <algorithm> #define foror(i,a,b) for(i=a;i<b;i++) #define foror2(i,a,b) for(i=a;i>b;i--) #define EPS 1.0e-6 #define PI acos(-1.0) #define INF 3000000000 #define MOD 1000000009 #define mem(a,b) memset((a),b,sizeof(a)) #define TS printf("!!!\n") #define lson o<<1, l, m #define rson o<<1|1, m+1, r //using ll = long long; //using ull= unsigned long long; //std::ios::sync_with_stdio(false); using namespace std; //priority_queue<int,vector<int>,greater<int>> que; typedef long long ll; int ans; char s[110][110]; int dir[4][2]; int bit[50]; int n,m; int cal(int n) { int ans=0 ; for (ans=0;n;ans++) { n&=(n-1); } return ans; } void dfs(int row,int pass,int now) { if(row==n) { int cur=max(pass,cal(now)); ans=min(ans,cur); return ; } dfs(row+1,pass+1,now); dfs(row+1,pass,now|bit[row]); } int main() { freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); dir[0][0]=-1,dir[0][1]=0; dir[1][0]=1,dir[1][1]=0; dir[2][0]=0,dir[2][1]=1; dir[3][0]=0,dir[3][1]=-1; cin >> n >> m; ans=min(n,m); for(int i=0;i<n;i++) { scanf("%s",s[i]); for(int j=0;j<m;j++) if(s[i][j]=='*') bit[i]|=(1<<j); } dfs(0,0,0); cout<<ans<<endl; return 0; }
D:BFS+SG函数 :如果一个点是必胜点 那么他后面和前面的点一定不是必胜点 反之一个点不是必胜点 那么他前面和后面的点的后继如果有必胜点 则他不是必胜点 如果没有 则他是必胜点
while(set.find(x)!=set.end()) x++ 当set为空时 返回1 当set为0-y连续的时 返回的是y+1 当0-y有缺少时 返回的是第一个缺少的数
#include <bits/stdc++.h> #include <cstring> #include <iostream> #include <algorithm> #define foror(i,a,b) for(i=a;i<b;i++) #define foror2(i,a,b) for(i=a;i>b;i--) #define EPS 1.0e-6 #define PI acos(-1.0) #define INF 3000000000 #define MOD 1000000009 #define mem(a,b) memset((a),b,sizeof(a)) #define TS printf("!!!\n") #define lson o<<1, l, m #define rson o<<1|1, m+1, r //using ll = long long; //using ull= unsigned long long; //std::ios::sync_with_stdio(false); using namespace std; //priority_queue<int,vector<int>,greater<int>> que; typedef long long ll; vector<int> tree[1005]; //vector<int> newtree[1005]; int visit[1005]; int n,m; int sg[1005]; queue<int> que; void bfs() { visit[1]=1; while(!que.empty()) { int cur=que.front(); que.pop(); for(int i=0;i<tree[cur].size();i++) { if(visit[tree[cur][i]]==0) { visit[tree[cur][i]]=visit[cur]+1; que.push(tree[cur][i]); } } } } /*void rebuild() { for(int i=1;i<=n;i++) { for(int j=0;j<tree[i].size();i++) { if(visit[tree[i][j]]>visit[i]) newtree[i].push_back(tree[i][j]); } } }*/ int sgdfs(int x) { if(sg[x]!=-1) return sg[x]; int zero=0; //one=-1; set<int> a; for(int i=0;i<tree[x].size();i++) { if(visit[tree[x][i]]>visit[x]) a.insert(sgdfs(tree[x][i])); } while(a.find(zero)!=a.end()) zero++; sg[x]=zero; return sg[x]; } int main() { freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); mem(sg,-1); mem(visit,0); cin >> n >> m; int s,f; for(int i=1;i<=m;i++) { scanf("%d %d",&s,&f); tree[s].push_back(f); tree[f].push_back(s); } que.push(1); bfs(); //rebuild(); int ans=sgdfs(1); if(ans) cout<<"Vladimir"; else cout<<"Nikolay"; //for(int i=1;i<=n;i++) //ans=max(ans,visit[i]); return 0; }
F:浮标
因为间距的单调不会使得答案单调,间距过大过小都会使得最后的移动距离不是最优,所以是使用三分而不是二分
对于每次三分,每次在n个点里面假设一个点不动,然后枚举完算一遍,取最优。
while(fabs(r - l) > eps) { double mid = (l + r) / 2.0; double midd = (mid + r) / 2.0; if(cal(mid, 0) > cal(midd, 0)) l = mid; else r = midd; } double ans = cal(l, 0) > cal(r, 0) ? r : l;
#include <bits/stdc++.h> using namespace std; #define N 405 const double eps = 1e-12; double num[N]; int n, id; double cal(double x, int flag) { double res = 0, ans = 100000000; for(int st = 1; st <= n; st++) { res = 0; for(int i = 1; i < st; i++) res += fabs(num[st] - (st - i) * x - num[i]); for(int i = st + 1; i <= n; i++) res += fabs(num[st] + (i - st) * x - num[i]); if(ans > res) ans = res, id = st; } return ans; } void solve() { scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%lf", &num[i]); double l = 0, r = 100000000; while(fabs(r - l) > eps) { double mid = (l + r) / 2.0; double midd = (mid + r) / 2.0; if(cal(mid, 0) > cal(midd, 0)) l = mid; else r = midd; } double ans = cal(l, 0) > cal(r, 0) ? r : l; double res = cal(ans, 1); printf("%.4f\n", res); for(int i = 1; i < id; i++) printf("%.10f ", num[id] - (id - i) * ans); printf("%.10f ", num[id]); for(int i = id + 1; i <= n; i++) printf("%.10f ", num[id] + (i - id) * ans); } int main() { freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); solve(); return 0; }
G:在线-->可持久化线段树(主席树 离线-->权值线段树
#include<bits/stdc++.h> using namespace std; const int maxn=1000007; struct { int l,r,loca; }tr[maxn*40]; int tot,A[maxn],rt[maxn]; void pushup(int x){ tr[x].loca=min(tr[tr[x].l].loca,tr[tr[x].r].loca); } void insert(int &x,int l,int r,int a,int b){ tr[++tot]=tr[x]; x=tot; if(l==r){ tr[x].loca=b; return ; } int mid=(l+r)>>1; if(a<=mid) insert(tr[x].l,l,mid,a,b); else insert(tr[x].r,mid+1,r,a,b); pushup(x); } int query(int x,int l,int r,int a){ if(l==r)return l; int mid=(l+r)/2; if(tr[tr[x].l].loca<a) return query(tr[x].l,l,mid,a); else return query(tr[x].r,mid+1,r,a); } int main(){ int n,m; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&A[i]); insert(rt[i]=rt[i-1],0,1000001,A[i],i); } scanf("%d",&m); while(m--){ int a,b; scanf("%d%d",&a,&b); printf("%d\n",query(rt[b],0,1000001,a)); } }
I:莫队
K:可持久化并查集