第一周周练

中国(北方)大学生程序射击训练赛(第一周)

官方题解 

A.Prufer序列

暴力枚举每一个点,删除改点后生成树计数,但1e8为什么不超时。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int mod=1000000007;
LL pow_mod(LL a,LL n){
    LL t=a,res=1;
    while(n){
        if(n&1) res=(res*t)%mod;
        t=(t*t)%mod;
        n/=2;
    }
    return res;
}
LL inv(LL a,LL m){
    return pow_mod(a,m-2);
}
struct Matrix{
    int mat[105][105];
    void init(){
        memset(mat,0,sizeof(mat));
    }
    int det(int n){
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                mat[i][j]=(mat[i][j]%mod+mod)%mod;
        int res=1;
        for(int i=0;i<n;i++){
            for(int j=i;j<n;j++)
                if(mat[j][i]!=0){
                    for(int k=i;k<n;k++)
                        swap(mat[i][k],mat[j][k]);
                    if(i!=j)
                        res=(-res+mod)%mod;
                    break;
                }
            if(mat[i][i]==0){
                res=-1;
                break;
            }
            for(int j=i+1;j<n;j++){
                int mut=((LL)mat[j][i]*inv(mat[i][i],mod))%mod;
                for(int k=i;k<n;k++)
                    mat[j][k]=(mat[j][k]-((LL)mat[i][k]*mut)%mod+mod)%mod;
            }
            res=((LL)res*mat[i][i])%mod;
        }
        return res;
    }
};
Matrix ret;
int g[105][105];
int in[105];
int t,n,m;
void pre(int x){
    ret.init();
    for(int i=0;i<n;i++){
        if(i==x) continue;
        int ii=i;
        if(i>x&&x!=-1) ii--;
        for(int j=0;j<n;j++){
            if(i==j||j==x) continue;
            int jj=j;
            if(j>x&&x!=-1) jj--;
            if(g[i][j]){
                ret.mat[ii][jj]=-1;
                ret.mat[ii][ii]++;
            }
        }
    }
}
int main(){
    scanf("%d",&t);
    while(t--){
        memset(g,0,sizeof(g));
        memset(in,0,sizeof(in));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            g[u-1][v-1]=1;
            g[v-1][u-1]=1;
            in[u-1]++;
            in[v-1]++;
        }
        pre(-1);
        int temp=ret.det(n-1);
        if(temp<0) temp++;
        int ans=(LL)temp*(n*(n+1)/2)%mod;
        for(int i=0;i<n;i++){
            pre(i);
            int temp=ret.det(n-2);
            if(temp<0) temp++;
            ans-=(LL)(in[i]*(i+1)%mod)*temp%mod;
            if(ans<0) ans+=mod;
        }
        printf("%d
",ans);
    }

    return 0;
}
Psong

B.埃蒙的时空航道

最大流,直接不行,反过来求最小割。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long LL;
LL n,c;
LL p[100005];
LL s[100005];
LL w[100005];
int main(){
    scanf("%lld%lld",&n,&c);
    for(LL i=1;i<=n;i++)
        scanf("%lld",&p[i]);
    for(LL i=1;i<=n;i++)
        scanf("%lld",&s[i]);
    LL sum=0,ans=1e18;
    for(LL i=1;i<=n;i++){
        w[i]=p[i]-s[i]+(i-1)*c;
        sum+=s[i];
    }
    sort(w+1,w+1+n);
    for(LL i=1;i<=n;i++){
        sum+=w[i]-(i-1)*c;
        ans=min(ans,sum);
    }
    printf("%lld
",ans);

    return 0;
}
Psong

C.Shadow of Survival

D.数学题

二分答案,尺取判断。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const double eps=1e-8;
const int N=100005;
int n,m,k;
int a[N],b[N];
bool check(double mid){
    //cout<<"mid="<<mid<<endl;
    int num=0;
    int L=1,R=1;
    while(1){
        if(R>n) break;
        double temp=(1.0*a[L])/b[R];
        //cout<<L<<" "<<R<<" ";
        //cout<<temp<<endl;
        if(mid-temp>eps&&L<n) L++;
        else if(mid-temp>eps&&L==n) R++;
        else{
            num+=n-L+1;
            //cout<<"num="<<num<<endl;
            R++;
        }
        //cout<<endl;
    }
    //cout<<"num="<<num<<endl;
    //system("pause");
    if(num>=k) return true;
    else return false;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        sort(a+1,a+1+n);
        for(int i=1;i<=m;i++)
            scanf("%d",&b[i]);
        sort(b+1,b+1+m);
        double l=0,r=1.0*a[n]/b[1];
        while(abs(r-l)>eps){
            double mid=(l+r)/2;
            if(check(mid)) l=mid;
            else r=mid;
        }
        printf("%.2lf
",l);
    }

    return 0;
}
Psong

E.Water Problem

矩阵快速幂。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
const LL s1=1e9+7;
struct Mat{
    LL a[5][5];
    void init(){
        a[0][0]=5;a[0][1]=3;a[0][2]=0;a[0][3]=0;a[0][4]=1;
        a[1][0]=3;a[1][1]=2;a[1][2]=0;a[1][3]=0;a[1][4]=1;
        a[2][0]=2;a[2][1]=1;a[2][2]=0;a[2][3]=0;a[2][4]=1;
        a[3][0]=1;a[3][1]=1;a[3][2]=0;a[3][3]=0;a[3][4]=0;
        a[4][0]=0;a[4][1]=0;a[4][2]=0;a[4][3]=0;a[4][4]=1;
    }
};
Mat operator *(Mat a,Mat b){
    Mat c;
    for(LL i=0;i<5;i++)
    for(LL j=0;j<5;j++){
        c.a[i][j]=0;
        for(LL k=0;k<5;k++)
            c.a[i][j]+=a.a[i][k]*b.a[k][j];
            c.a[i][j]%=s1;
    }
    return c;
}
Mat operator ^(Mat p,LL k){
    Mat ans; ans.init();
    while(k){
        if(k&1)
            ans=ans*p;
        k/=2;
        p=p*p;
    }
    return ans;
}
int main(){
    LL f1,f2,f3,f4,n;
    while(cin>>f1>>f2>>n){
        f3=f1+f2;
        f4=f2+f3-1;
        Mat x;
        memset(x.a,0,sizeof(x.a));
        x.a[0][0]=f4%s1;
        x.a[1][0]=f3%s1;
        x.a[2][0]=f2%s1;
        x.a[3][0]=f1%s1;
        x.a[4][0]=1;
        Mat a; a.init();
        Mat ans=x;
        if(n>4) ans=(a^((n-1)/4-1))*x;
        for(int i=0;i<5;i++){
            for(int j=0;j<5;j++){
                //cout<<ans.a[i][j]<<" ";
            }
            //cout<<endl;
        }
        cout<<ans.a[3-(n-1)%4][0]%s1<<endl;
    }

    return 0;
}
Psong

F.等差区间

线段树或者ST表统计区间最大,最小,gcd以及是否有相同的数字。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#define lson (id*2)
#define rson (id*2+1)
#define mid ((l+r)/2)
using namespace std;
const int N=1e5+5;
int gcd(int x,int y){
    return y==0?x:gcd(y,x%y);
}
struct node{
    int mi,ma,p;
} tre[N*5];
void push_up(int id){
    tre[id].ma=max(tre[lson].ma,tre[rson].ma);
    tre[id].mi=min(tre[lson].mi,tre[rson].mi);
    tre[id].p=max(tre[lson].p,tre[rson].p);
}
void build(int id,int l,int r){
    if(l==r){
        tre[id].ma=0;
        tre[id].mi=0;
        tre[id].p=0;
        return;
    }
    build(lson,l,mid);
    build(rson,mid+1,r);
    push_up(id);
    return;
}
void add(int id,int l,int r,int pos,int tt){
    if(l==r){
        tre[id].ma=tt;
        tre[id].mi=tt;
        return;
    }
    if(pos<=mid)
        add(lson,l,mid,pos,tt);
    else
        add(rson,mid+1,r,pos,tt);
    push_up(id);
    return;
}
void add_pos(int id,int l,int r,int pos,int tt){
    if(l==r){
        tre[id].p=tt;
        return;
    }
    if(pos<=mid)
        add_pos(lson,l,mid,pos,tt);
    else
        add_pos(rson,mid+1,r,pos,tt);
    push_up(id);
    return;
}
int query_max(int id,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr){
        return tre[id].ma;
    }
    int ans=0;
    if(ql<=mid)
        ans=max(ans,query_max(lson,l,mid,ql,qr));
    if(qr>mid)
        ans=max(ans,query_max(rson,mid+1,r,ql,qr));
    return ans;
}
int query_min(int id,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr){
        return tre[id].mi;
    }
    int ans=1e9+7;
    if(ql<=mid)
        ans=min(ans,query_min(lson,l,mid,ql,qr));
    if(qr>mid)
        ans=min(ans,query_min(rson,mid+1,r,ql,qr));
    return ans;
}
int query_num(int id,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr){
        return tre[id].p;
    }
    int ans=0;
    if(ql<=mid)
        ans=max(ans,query_num(lson,l,mid,ql,qr));
    if(qr>mid)
        ans=max(ans,query_num(rson,mid+1,r,ql,qr));
    return ans;
}
int tre_gcd[N*5];
void push_up_gcd(int id){
    tre_gcd[id]=gcd(tre_gcd[lson],tre_gcd[rson]);
    return;
}
void build_gcd(int id,int l,int r){
    if(l==r){
        tre_gcd[id]=0;
        return;
    }
    build_gcd(lson,l,mid);
    build_gcd(rson,mid+1,r);
    push_up_gcd(id);
    return;
}
void add_gcd(int id,int l,int r,int pos,int tt){
    if(l==r){
        tre_gcd[id]=tt;
        return;
    }
    if(pos<=mid)
        add_gcd(lson,l,mid,pos,tt);
    else
        add_gcd(rson,mid+1,r,pos,tt);
    push_up_gcd(id);
    return;
}
int query_gcd(int id,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr){
        return tre_gcd[id];
    }
    int ans=-1;
    if(ql<=mid)
        ans=query_gcd(lson,l,mid,ql,qr);
    if(qr>mid){
        if(ans!=-1)
            ans=gcd(ans,query_gcd(rson,mid+1,r,ql,qr));
        else
            ans=query_gcd(rson,mid+1,r,ql,qr);
    }
    return ans;
}
int x[N];
int pos[N*10];
int main(){
    int n,q;
    while(scanf("%d%d",&n,&q)!=EOF){
        build(1,1,n);
        build_gcd(1,1,n);
        memset(pos,0,sizeof(pos));
        for(int i=1;i<=n;i++){
            scanf("%d",&x[i]);
            add(1,1,n,i,x[i]);
            add_pos(1,1,n,i,pos[x[i]]);
            pos[x[i]]=i;
        }
        for(int i=1;i<n;i++){
            add_gcd(1,1,n-1,i,abs(x[i+1]-x[i]));
        }
        for(int i=1;i<=q;i++){
            int L,R;
            scanf("%d%d",&L,&R);
            int x1=query_max(1,1,n,L,R);
            int x2=query_min(1,1,n,L,R);
            int ok=query_num(1,1,n,L,R);
            //cout<<ok<<endl;
            if(x1==x2||(R-L)<=1){
                printf("Yes
");
            }
            else{
                if(ok<L){
                    int x3=query_gcd(1,1,n-1,L,R-1);
                    if((x1-x2)==x3*(R-L)) printf("Yes
");
                    else printf("No
");
                }
                else printf("No
");
            }
        }

    }

    return 0;
}
Psong
原文地址:https://www.cnblogs.com/N-Psong/p/6558096.html