由于很菜,只过了BCDF4题,其中C是队友切的,赛后又过了J,所以写一下BDFJ四道题题解。

B

这道题卡了不少人,我也被卡了一会(罚时3次),其实不算难。
首先可以O(n^2)统计出所有可能的圆心(显然最优解一定至少满足原点和任意另外两点构成的圆,除非只能经过1点)。然后判断每个点出现的次数即可。
然而这道题恶心的地方是一共2e6个点,如果用map统计次数会卡常超时(map的常数太大了)。解决方法是直接排序之后计数即可。

#include<bits/stdc++.h>
using namespace std;
#define eps 1e-10
struct Point{
    double x,y;
    Point(double x,double y){
        this->x=x;
        this->y=y;
    }

    Point(){
        x=y=0;
    }
};
Point p[5000];
//过三点求圆心坐标
Point waixin(Point a,Point b,Point c)
{
  double a1 = b.x - a.x, b1 = b.y - a.y, c1 = (a1*a1 + b1*b1)/2;
  double a2 = c.x - a.x, b2 = c.y - a.y, c2 = (a2*a2 + b2*b2)/2;
  double d = a1*b2 - a2*b1;
  return Point(a.x + (c1*b2 - c2*b1)/d, a.y + (a1*c2 -a2*c1)/d);
}
pair<double,double> m[2222222];
int main(){
    int n,i,j=0,k=0;
    cin>>n;
    for(i=0;i<n;i++){
        cin>>p[i].x>>p[i].y;
    }
    Point z(0,0);
    for(i=0;i<n;i++){
        for(j=i+1;j<n;j++){
            if(fabs(p[i].x*p[j].y-p[i].y*p[j].x)>eps){
                Point temp=waixin(p[i],p[j],z);
               // cout<<p[i].x<<" "<<p[i].y<<" "<<p[j].x<<" "<<p[j].y<<" "<<temp.x<<" "<<temp.y<<endl;
                m[k++]=make_pair(temp.x,temp.y);
            }

        }
    }
    if(k==0){cout<<1;return 0;}
    sort(m,m+k);
    int cnt=1,ma=1;
    for(i=0;i<k-1;i++){
        if(fabs(m[i].first-m[i+1].first)<eps&&fabs(m[i].second-m[i+1].second)<eps)cnt++,ma=max(ma,cnt);
        else cnt=1;
    }

    for(i=1;i<=n;i++)if(i*(i-1)==2*ma)break;
    cout<<i;
}

D

签到题。只用算出两个时间对应秒数,然后abs就行了。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int a1,a2,a3,b1,b2,b3;
    scanf("%d:%d:%d",&a1,&a2,&a3);
    scanf("%d:%d:%d",&b1,&b2,&b3);
    int t1=a1*3600+a2*60+a3;
    int t2=b1*3600+b2*60+b3;
    cout<<abs(t1-t2);

}

F

首先用gcd把矩阵全部算出来,然后用两次单调队列就能算出每个小正方形的最大值了。

#include<bits/stdc++.h>
using namespace std;
#define eps 1e-10
int a[5005][5005];
int dp[5005][5005];
struct node{
    int id;
    int val;
}tmp;



int gcd(int x,int y){
    return x%y==0?y:gcd(y,x%y);
}
int lcm(int x,int y){
    return x*y/gcd(x,y);
}
int main(){
    int i,n,m,j,k;
    cin>>n>>m>>k;
    for(i=1;i<=n;i++){
        for(j=1;j<=m;j++){
            a[i][j]=lcm(i,j);
        }
    }

    for(i=1;i<=n;i++){
        deque<node>maxn;
        for(j=1;j<=m;j++){
            if(!maxn.empty() && j-maxn.front().id>=k) maxn.pop_front();
            while(!maxn.empty() && maxn.back().val<a[i][j]) maxn.pop_back();

            tmp.val=a[i][j];
            tmp.id=j;
            maxn.push_back(tmp);

            if(j>=k)
            {

                dp[i][j]=maxn.front().val;
            }
        }
    }

    long long sum=0;
    for(j=k;j<=m;j++){
        deque<node>maxn;
        for(i=1;i<=n;i++){
            if(!maxn.empty() && i-maxn.front().id>=k) maxn.pop_front();
            while(!maxn.empty() && maxn.back().val<dp[i][j]) maxn.pop_back();

            tmp.val=dp[i][j];
            tmp.id=i;
            maxn.push_back(tmp);

            if(i>=k)
            {

                sum+=maxn.front().val;
            }
        }
    }
    cout<<sum<<endl;
}

J

这道题赛中没过,赛后过的。
最开始的思路是:现在知道了k次以后的情况,对于每个大小为p的cycle而言,变换p次之后又会回到初始状态。因此计算所有cycle大小的lcm,求k对这个lcm的逆元就可以了。
然而这个方案并不可行,因为这个lcm有可能是个天文数字,逆元基本没办法去求。
赛后想到的解决方案是:由于每个cycle是独立的,因此也可以独立的计算每个cycle每次转换的情况,这样单独求k关于每个p的逆元之后单独解决就行了。
ps:cycle指每个数变换成自己经历的所有数的一个循环。例如;2 3 1 5 4而言,有1->2->3和4->5这两个cycle。
为什么求逆元就能解决?因为大小为p的cycle,变换p次一定能得到它本身。现在已知变换k次的情况,求变换1次的情况,那么只要求出k在模p意义下的逆元x。变换x次【变换k次】,最终和变换1次就是等价的了。
关于最终的变换x次的求法,我用的是倍增来解决的。求出初始排列的1次变换、2次变换、4次变换、8次变换的结果,这样根据二进制就能表达出所有变换的情况。

#include<bits/stdc++.h>
using namespace std;
#define eps 1e-10
#define ll long long
int mod;

int a[111111],visited[111111];
int dp[111111][20],out[111111][2];
int main(){
    ll i,n,m,j,k;
    cin>>n>>k;
    for(i=1;i<=n;i++){
        cin>>a[i];
        dp[i][0]=a[i];
        out[i][0]=i;
    }

    ll tt=i;
    //cout<<tt<<endl;
    for(j=1;j<20;j++){
        for(i=1;i<=n;i++){
            dp[i][j]=dp[dp[i][j-1]][j-1];
          //  cout<<dp[i][j]<<" ";
        }
       // cout<<endl;
    }
    for(i=1;i<=n;i++){
        vector<int>v;
        j=i;
        if(visited[i])continue;
        while(!visited[j]){
            v.push_back(j);
            visited[j]=1;
            j=a[j];
        }
        int temp=k%v.size();
        for(j=1;j<v.size();j++)if(temp*j%v.size()==1)break;
        for(int kk=0;kk<20;kk++){
            if(j&1){
                for(int h=0;h<v.size();h++)out[v[h]][1]=out[dp[v[h]][kk]][0];
                for(int h=0;h<v.size();h++)out[v[h]][0]=out[v[h]][1];
            }
            j/=2;
        }
    }

    for(i=1;i<=n;i++)cout<<out[i][0]<<" ";


}

ps。由于急着去吃饭就不markdown排版了,大家凑合看吧QAQ