赛前随便选了一场 CF Div 1
一棵树,每个点上可以是0或者1.对某个点的一次操作可以使自己,自己孙子,自己孙子的孙子....的权值翻转,求最少翻转多少次和翻转的点编号。
dfs,贪心地尽量翻转深度小的点即可。
#include <cstdio>
#include <iostream>
#include <string.h>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=100005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
const ld pi=acos(-1.0L);
int head[maxn],a[maxn],b[maxn];
bool visit[maxn];
int num,ans;
vector<int> v;
struct Edge {
int from, to, pre;
};
Edge edge[maxn*2];
void addedge(int from, int to) {
edge[num] = (Edge) {from, to, head[from]};
head[from] = num++;
edge[num] = (Edge) {to, from, head[to]};
head[to] = num++;
}
void dfs(int now,int s1,int s2) {
visit[now]=1;
int flag=0;
if (a[now]^s2!=b[now]) ans++,flag=1,v.push_back(now);
for (int i=head[now];i!=-1;i=edge[i].pre) {
int to=edge[i].to;
if (!visit[to])
dfs(to,s2^flag,s1);
}
}
int main() {
int n,x,y,i,j;
scanf("%d",&n);
num=0;
memset(head,-1,sizeof(head));
for (i=1;i<n;i++) {
scanf("%d%d",&x,&y);
addedge(x,y);
}
for (i=1;i<=n;i++) scanf("%d",&a[i]);
for (i=1;i<=n;i++) scanf("%d",&b[i]);
mem0(visit);ans=0;
dfs(1,0,0);
printf("%d\n",ans);
for (i=0;i<v.size();i++) {
printf("%d\n",v[i]);
}
return 0;
}
这题有点像经典题传纸条。
一个矩阵,两个人中其中一个从左上到右下,另一个左下到右上。显然两人的路径会相遇一次,相遇格子的价值不计,其余格子的价值计算一次,问两个人所走路径的权值和最大是多少。
DP。先预处理从四个角到某点的最大权值和,再枚举相遇的格子,用四个方向到这个格子的最大权值加起来更新答案。
#include <cstdio>
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=1005;
ll dp[5][maxn][maxn];
ll a[maxn][maxn];
int main() {
int n,m,i,j,k;
scanf("%d%d",&n,&m);
memset(dp,0,sizeof(dp));
for (i=1;i<=n;i++) {
for (j=1;j<=m;j++) {
scanf("%lld",&a[i][j]);
}
}
dp[1][1][1]=a[1][1];
for (i=1;i<=n;i++) {
for (j=1;j<=m;j++) {
dp[1][i+1][j]=max(dp[1][i+1][j],dp[1][i][j]+a[i+1][j]);
dp[1][i][j+1]=max(dp[1][i][j+1],dp[1][i][j]+a[i][j+1]);
// cout << dp[1][i][j] << endl;
}
}
dp[2][1][m]=a[1][m];
for (i=1;i<=n;i++) {
for (j=m;j>=1;j--) {
dp[2][i+1][j]=max(dp[2][i+1][j],dp[2][i][j]+a[i+1][j]);
dp[2][i][j-1]=max(dp[2][i][j-1],dp[2][i][j]+a[i][j-1]);
}
}
dp[3][n][1]=a[n][1];
for (i=n;i>=1;i--) {
for (j=1;j<=m;j++) {
dp[3][i-1][j]=max(dp[3][i-1][j],dp[3][i][j]+a[i-1][j]);
dp[3][i][j+1]=max(dp[3][i][j+1],dp[3][i][j]+a[i][j+1]);
}
}
dp[4][n][m]=a[n][m];
for (i=n;i>=1;i--) {
for (j=m;j>=1;j--) {
dp[4][i-1][j]=max(dp[4][i-1][j],dp[4][i][j]+a[i-1][j]);
dp[4][i][j-1]=max(dp[4][i][j-1],dp[4][i][j]+a[i][j-1]);
}
}
ll ans=0;
for (i=2;i<=n-1;i++) {
for (j=2;j<=m-1;j++) {
ans=max(ans,dp[1][i-1][j]+dp[4][i+1][j]+dp[2][i][j+1]+dp[3][i][j-1]);
ans=max(ans,dp[1][i][j-1]+dp[4][i][j+1]+dp[2][i-1][j]+dp[3][i+1][j]);
}
}
printf("%lld\n",ans);
return 0;
}
给你一个数列,问(i-j)^2+(sum[i]-sum[j])^2的最小值。
把每个(i,sum[i])看做平面的一个点,转化为最近点对问题分治进行求解。
#include <cstdio>
#include <iostream>
#include <string.h>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=100005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
const ld pi=acos(-1.0L);
ll a[maxn];
int tem[maxn];
struct Point{
int x,y;
};
Point p[maxn];
bool cmp(Point a,Point b) {
return a.x<b.x || (a.x==b.x&&a.y<b.y);
}
bool cmpy(int a,int b) {
return p[a].y<p[b].y;
}
ll sqr(ll x) {
return x*x;
}
ll dfs(int l,int r) {
if (l==r) return llinf;
if (l+1==r) return sqr(p[l].x-p[r].x)+sqr(p[l].y-p[r].y);
int mid=(l+r)/2;
ll d1=dfs(l,mid),d2=dfs(mid+1,r),ans;
ans=min(d1,d2);
int i,j,m=0;
for (i=l;i<=r;i++)
if (sqr(p[i].x-p[mid].x)<=ans) tem[m++]=i;
sort(tem,tem+m,cmpy);
for (i=0;i<m;i++)
for (j=i+1;j<m&&sqr(p[tem[i]].y-p[tem[j]].y)<ans;j++)
ans=min(ans,sqr(p[tem[i]].x-p[tem[j]].x)+sqr(p[tem[i]].y-p[tem[j]].y));
return ans;
}
int main() {
int n,i;
scanf("%d",&n);
ll sum=0;
for (i=1;i<=n;i++) {
scanf("%I64d",&a[i]);
sum+=a[i];
p[i].x=i;p[i].y=sum;
}
// sort(p+1,p+n+1,cmp);
ll ans=dfs(1,n);
printf("%I64d\n",ans);
return 0;
}
E. Points and Segments 欧拉回路,很有趣的一道题。