A. Cancel the Trains
思路:相撞的时候会在对角线相撞 那么统计对角线即可
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+10;
bool st[N];
int main(){
int T;
cin>>T;
while(T--){
memset(st,0,sizeof st);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
st[x]=1;
}
int res=0;
for(int i=1;i<=m;i++){
int x;
scanf("%d",&x);
if(st[x])res++;
}
cout<<res<<endl;
}
return 0;
}
B. Suffix Operations
和前天的D很想 要是提前写了这个题 那么上大分了
思路:我从前往后统计出总和以后
分别从第一个到最后一个进行枚举求出min即为答案
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+10;
typedef long long LL;
LL a[N];
int main(){
int T;
cin>>T;
while(T--){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
LL ans=0,maxv=0;
for(int i=2;i<=n;i++){
ans+=max(a[i]-a[i-1],a[i-1]-a[i]);
}
if(n>=2){
maxv=max(a[2]-a[1],a[1]-a[2]);
maxv=max(maxv,max(a[n]-a[n-1],a[n-1]-a[n]));
}
for(int i=2;i<=n-1;i++){
maxv=max(maxv,-max(a[i+1]-a[i-1],a[i-1]-a[i+1])+max(a[i+1]-a[i],a[i]-a[i+1])+max(a[i-1]-a[i],a[i]-a[i-1]));
}
printf("%lld\n",ans-maxv);
}
return 0;
}
C. Triangles
题意:给出0-9数字的举行 问能形成最大的三角形
思路:枚举每一个点进行统计0-9数字中每一个数字的minx maxx maxy miny
然后再一次枚举进行统计答案 取max
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=2e3+10;
char g[N][N];
int minx[10],maxx[10],miny[10],maxy[10],ans[10];
int main(){
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%s",g[i]+1);
for(int i=0;i<=9;i++)minx[i]=miny[i]=n,maxx[i]=maxy[i]=0,ans[i]=0;;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
int x=g[i][j]-'0';
minx[x]=min(i,minx[x]);
maxx[x]=max(i,maxx[x]);
miny[x]=min(j,miny[x]);
maxy[x]=max(j,maxy[x]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
int x=g[i][j]-'0';
ans[x]=max(ans[x],max(max(i-minx[x],maxx[x]-i)*max(n-j,j-1),max(j-miny[x],maxy[x]-j)*max(n-i,i-1)));
}
for(int i=0;i<=9;i++)
printf("%d ",ans[i]);
puts("");
}
return 0;
}
D. Checkpoints
一个比较有趣的构造题 因为每一位都只能是偶数 不可能生产奇数 那么首先判断如果输入的是奇数那么输出-1
否则均可以通过构造生产 这里我们预处理出63种情况
通过二分来 减去find这个值后 直到为0 构造出游戏关卡
#include<iostream>
#include<cstring>
#include<algorithm>
#include<unordered_map>
#include<vector>
using namespace std;
typedef long long LL;
const int N=1e2+10;
LL f[N];
int main(){
for(int i=1;i<=63;i++)f[i]+=f[i-1]*2+2;
int T;
cin>>T;
while(T--){
LL n;
cin>>n;
if(n&1)puts("-1");
else{
vector<int>ans;
while(n){
int pos=upper_bound(f+1,f+1+63,n)-(f+1);
n-=f[pos];
ans.push_back(1);
for(int i=1;i<pos;i++)
ans.push_back(0);
}
printf("%d\n",ans.size());
for(int t:ans)
printf("%d ",t);
puts("");
}
}
}
E. Dog Snacks
题意:狗狗从1节点出发 他能寻找到距离他k内位置的食物 并沿着路径一直走 他走最优的情况下把整个地图全部吃完食物 最后全部吃完后并回到1点的位置也要小于等于k 求出k最小是多少
思路:一个很有意思的树形dp
考虑状态 我们递归返回的是
遍历完遍历一个节点他所有的子树后
返回到父亲所需要的最小距离k
即从子树返回到父亲所需要的最小k
如果该节点是叶子节 必然有k=1
如果该节点有多个子树那必然是即最短的子树的k+1
我们考虑了从子树返回到父亲后所返回的状态
这时候ans均取k的最大值
但这还是不够的我们只考虑的父亲和儿子的转移
但没有考虑儿子之间的转移
我们接着分析 一个节点中 几个子树的转移
从子树中转移到另一个子树 k最大必然是最深的子树的k+1
如果这个点是根节点1
那么最深的子树不需要转移到别的节点 只需要回到根节点
但是次大子树有可能和最大子树相等
那么这时候我们取ans取max(k,`k+1)
在所有的k的取值中我们取max即为最终结果
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N=2e5+10;
struct Edge{
int v,next;
}edge[N<<1];
int head[N],tot,degree[N],ans,T;
void init(){
memset(head,0,sizeof head);
tot=0;
memset(degree,0,sizeof degree);
ans=0;
}
void add(int u,int v){
edge[++tot]={v,head[u]};
head[u]=tot;
}
int dfs(int u,int fa){
if(degree[u]==1&&u!=1)return 1;//一个叶子节点
vector<int>tmp;
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].v;
if(v!=fa){
tmp.push_back(dfs(v,u));//能访问完子树的最小K 子树返回不做考虑
}
}
sort(tmp.begin(),tmp.end());//最大的到最小的距离
if(tmp.size()>1){
if(u==1)ans=max({ans,tmp.back(),tmp[tmp.size()-2]+1});
//是根节点那么从次长子树+1转移到最长子树的花费 或者最长子树最大长度
else ans=max(ans,tmp.back()+1);//不是根节点 回到父亲的最短路径
}
else ans=max(ans,tmp[0]);//只有一个子树
return tmp[0]+1;//能访问完子树的最小K 子树返回不做考虑
}
int main(){
scanf("%d",&T);
while(T--){
init();
int n;
scanf("%d",&n);
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
degree[u]++;
degree[v]++;
}
dfs(1,1);
printf("%d\n",ans);
}
return 0;
}