普及组的题目,感觉挺适合现在的我做的。。。。
前两题可以无压力AC的,第三题想不出来了,第四题可惜没去试一试。
A 战争尾声
题意:
给一个200*200的矩形,放在平面直角坐标系中。给n个点,问能否找到一个点到所有n个点的距离相同。n的坐标要求是正整数。n<=200。
思路:
题目保证答案是正整数,那么我们暴力枚举就可以了。
复杂度O(n^3)
类型:
暴力、模拟
代码:#include<bits/stdc++.h> using namespace std; int x[222],y[222],n; double juli(int x1,int y1,int x2,int y2){ return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } bool solve(int xx,int yy){ double delta=juli(xx,yy,x[1],y[1]); for(int i=2;i<=n;i++){ double tmp=juli(xx,yy,x[i],y[i]); if(fabs(tmp-delta)>=0.0001)return false; } return true; } int main() { cin>>n; for(int i=1;i<=n;i++){ cin>>x[i]>>y[i]; } int f=0; for(int i=1;i<=200;i++){ for(int j=1;j<=200;j++){ if(solve(i,j)){ cout<<i<<' '<<j<<endl; f=1; break; } } if(f)break; } if(f==0)cout<<"War is cruel."<<endl; return 0; }
B 签订协议
题意:
给一个环,环上一共有n个点编号为1-n并且按照顺时针排序。每个点有一个战力值,每次从1-n会转一圈传递协议,要求先传给战力值高的点。每转一圈算一个轮回,问需要转多少个轮回让所有的点都拿到协议。
思路:
纸上手模一下应该能够很快知道解法。
可以先将点按照战力值进行排序,从排序后的第一个点开始往后扫,每次比较相邻的两个点的编号大小,假设编号是a[i]和a[i+1],如果a[i]<a[i+1],说明这一轮可以从a[i]传给a[i+1],如果a[i]>a[i+1]了,那么说明这一轮传不到了,只能下一轮了,而且本轮的传递结束了。
因此我们只要扫一遍,比较相邻的两个点的编号,如果遇到a[i]>a[i+1]就ans++。#include<bits/stdc++.h> using namespace std; int n; struct node{ int a,idx; }p[800005]; bool cmp(node x,node y){ return x.a>y.a; } int main() { cin>>n; for(int i=1;i<=n;i++){ int x; scanf("%d",&x); p[i].a=x; p[i].idx=i; } int ans=1; sort(p+1,p+1+n,cmp); for(int i=1;i<n;i++){ if(p[i].idx>p[i+1].idx)ans++; } cout<<ans<<endl; return 0; }
C 照顾小猫
数学太差,看到这种题经常一筹莫展。看了一会,感觉是容斥,但是不知道怎么做,因为我只知道有容斥这个东西,具体怎么分析不会做。。
然后瞄了一眼题解,看是看懂了,但是感觉和我理解的容斥好像用法不太一样?
首先我们考虑没有限制的时候的方案数,对于一只猫来说,长度为i的话,存在方案数26^1+26^2+26^3+...26^i种,这个用一个前缀和sum[i]可以表示出来。
此时再来一只猫,最大长度为j,假设i<j,这只猫的无限制方案数就是sum[j],由于j猫的名字不能和i猫的名字一样,那么j猫的名字方案数就是sum[j]-1
如果再来一只猫,最大长度为k,无限制方案为sum[k],k猫不能和前面的猫的名字相同,所以又sum[k]-2种
因此第m只猫的方案数就是sum[a[m]-m+1
答案就是全部乘起来就好了。注意要先对a[i]数组排序,保证后面的字符串一定会受到前面的影响。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int mod=77797; int n,a[10005],num[105],sum[105]; void init(){ num[0]=1; for(int i=1;i<=10;i++)num[i]=num[i-1]*26%mod; for(int i=1;i<=10;i++)sum[i]=(sum[i-1]+num[i])%mod; } int main() { cin>>n; init(); for(int i=1;i<=n;i++)cin>>a[i]; sort(a+1,a+1+n); long long ans=1; for(int i=1;i<=n;i++){ if(sum[a[i]]<i){ cout<<-1<<endl; return 0; } ans=ans*(sum[a[i]]-i+1); ans=ans%mod; } cout<<ans<<endl; return 0; }
D 路线规划
题意不赘述了。本题的关键在于,要使得走过的路最少,在这个前提下再让时间尽量的少。其实看到了这个条件,考虑了一下最小生成树。但是他又要走回来,觉得会不会走回来换条更短的路(因为回来不需要再访问所有的点了)。但是现在想一想,如果换更短的路,由于路尽量少的限制,他不能走新路,只能走老路。只能走老路的情况下,我走过来的已经是最短的了,所以还是原路返回时间最少。
因此,构造一颗最小生成树,答案乘2就可以了。注意开long long
类型:
最小生成树
代码:include<bits/stdc++.h>
using namespace std;
int n,m,tot,f[200050];
struct node{
int u,v;
long long w;
bool operator < (const node & a)const {return w<a.w;
}
}p[2000500];
void init()
{
for(int i=0;i<200050;i++)f[i]=i;
}
int find(int x){
if(x!=f[x])return f[x]=find(f[x]);
return f[x];
}
int main()
{
init();
cin>>n>>m;
for(int i=1;i<=m;i++){int x,y; long long z; scanf("%d%d%lld",&x,&y,&z); p[i].u=x; p[i].v=y; p[i].w=z;
}
long long ans=0;
sort(p+1,p+1+m);
for(int i=1;i<=m;i++){int fx,fy; fx=find(p[i].u); fy=find(p[i].v); if(fx==fy)continue; ans+=p[i].w; f[fx]=fy;
}
cout<<ans*2<<endl;
return 0;
}