周一清楚姐姐问我题录好没。我还一脸懵逼,才知道周五就要考。
于是当晚放下了手中的理综,开始录题。
今天刚刚期末考完,题解是在比赛时候写的。
A 战争尾声
这道题就是一个非常友好的暴力题,但是因为开始出了些小问题,未标明答案的范围(其实在验题时候提到了,我在最后加了一个国家坐标都为整数,忘了说答案也都是整数了。好在开始时候发了一个公告)
40分解法:
想必大家看到数据范围了,最后有一句保证60%的数据有解,那么就说明有40%的可以直接骗分。
#头文件 int main (void){ cout<<"War is cruel."<<endl; return 0; }
100分解法:
计算一下距离,暴力过每一个点
时间复杂度最多为O()
#include<bits/stdc++.h> #define re register using namespace std; //快读输入,不用理会 inline char gc(){ static char buf[1000000],*p1 = buf,*p2 = buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++; } inline int read(){ re int ans = 0;re bool f = 1;re char ch = gc(); while(ch<'0'||ch>'9'){if (ch=='-')f = 0;ch = gc();} while(ch>='0'&&ch<='9'){ ans = (ans<<3)+(ans<<1)+(ch^48); ch = gc(); } return f?ans:~(ans-1); } int xi[256],yi[256];//国家坐标 int n; bool check(int x,int y){ double dis = sqrt((x-xi[1])*(x-xi[1])+(y-yi[1])*(y-yi[1])); for(int i=2;i<=n;++i){ double tem = sqrt((x-xi[i])*(x-xi[i])+(y-yi[i])*(y-yi[i])); if(fabs(dis-tem)>=0.0001)return false; //请尽量使用fabs(),针对浮点数yuns } return true; }//判断这个点是否距离所有国家距离相等 signed main(void){ n = read(); for(int i=1;i<=n;++i){ xi[i] = read(); yi[i] = read(); } for(int i=1;i<=200;++i){ for(int j=1;j<=200;++j){ if(check(i,j)){ printf("%d %d",i,j); return 0; } } }//简单的暴力 printf("War is cruel."); return 0; }
B 签订协议
这道题是在出完上一道后想到的,就顺着写了下来,暴力大约可以拿到40分到60分,还是给的很足的。
至于正解很好想
100分解法
因为要从战斗力最高的国家开始,且协议书只能单向循环传递
我们给每个国家两个属性,一个是战斗力大小,一个是位置序号
我们将国家按战斗力由大到小排序后,前一个国家的位置如果大于当前国家的位置,那么轮数加一。
其实很好想嘛,如果有一个战斗力大的国家位置靠后,那么就只能先让这个国家签订,而当前国家需要等下一轮。
(这个算法挺常规的)
#include<bits/stdc++.h> using namespace std; struct nation{ int v,id; bool operator<(const nation & m)const{return v<m.v;} }na[800520]; int n; int main(void){ cin>>n; for(int i=1;i<=n;++i){ cin>>na[i].v; na[i].id=i; } sort(na+1,na+1+n); int ans=1; for(int i=n-1;i>=1;i--){ if(na[i].id<na[i+1].id)ans++; } cout<<ans<<endl; return 0; }
C 照看小猫
可能这道题是唯一有思维难度的吧,容斥原理。是很早以前想到的一道题(记得当时刚刚去电影院看完紫罗兰的剧场版)然后就想到了这道题。
100分解法
先预处理一下每种长度限制下的可能的所有情况。
(因为不想整高精度,于是名字长度限制的很小,最大才10)
然后从名字长度限制最短的挑起,做一下容斥,(高中数学也可以说是组合数吧)
#include<bits/stdc++.h> using namespace std; const int N = 1e4 + 520; long long n,m; long long num[15]; int l[N]; int main(){ num[1]=26; for(int i=2;i<=10;i++)num[i]=num[i-1]*26; for(int i=2;i<=10;i++)num[i]+=num[i-1];//预处理 cin>>n; for(int i=0;i<n;i++)cin>>l[i]; sort(l,l+n); long long ans=1; for(int i=0;i<n;i++){ m=num[l[i]]-i;//这只小猫的情况数-之前小猫的数量 if(m<=0){ cout<<-1<<endl; return 0; } m%=77797; ans=ans*m%77797; } cout<<ans<<endl; return 0; }
路线规划
这题我觉得是出的最水的一道,很早以前学最小生成树时候搞的
100分解法
仔细读完题后发现,有着最少路径的限制,于是我们知道我们要求一棵树,总时间最短,那就是一颗最小生成树。
//几乎就是最小生成树的板子 #include<bits/stdc++.h> using namespace std; struct edge{ long long u,v,w; }e[2000010]; int f[2000010]; int find(int x){ return x==f[x]?x:f[x]=find(f[x]); } bool cm(edge o0,edge o1){return o0.w<o1.w;} int main(void){ unsigned long long ans = 0; int n,m,cnt = 0,eu,ev; scanf("%d%d",&n,&m); for(register int i=1;i<=m;++i){ scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);e[i].w*=2; } for(register int i=1;i<=n;++i)f[i] = i; sort(e+1,e+m+1,cm); for(register int i=1;i<=m;++i){ eu = find(e[i].u);ev = find(e[i].v); if(eu==ev)continue; f[eu]=ev;ans+=e[i].w; if(++cnt==n-1)break; } cout<<ans; return 0; }
最后
第一次出题,还有很多没有注意到的地方,十分抱歉啊。
非常感谢大家参加这次普及组的比赛
写到这里的时候已经有40位大佬AK了。果然是我出的题太水了