周一清楚姐姐问我题录好没。我还一脸懵逼,才知道周五就要考。
于是当晚放下了手中的理综,开始录题。
今天刚刚期末考完,题解是在比赛时候写的。

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了。
果然是我出的题太水了