2018 Multi-University Training Contest 5

A
学习了一下题解,好像很牛逼啊,这个ll爆得也很灵性,tls牛逼啊。

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
ll one=1;
char buf[30000003];
ll rdp=0;
inline ll read(){
    ll ret=0;
    while(buf[rdp]>='0'&&buf[rdp]<='9'){
        ret*=10;
        ret+=buf[rdp++]-'0';
    }
    rdp++;
    return ret;
}
struct edge{
    ll u,v,w;
}a[200003],b[200003];
bool cmp(edge a,edge b){
    return a.w>b.w;
}
ll totb;
struct query{
    ll u,v,w;
}que[200003];
ll totq;

struct tedge{
    ll to,next,id;
}e[300003];
ll head[100003];
ll cnt;
ll pa[100003];
ll pid[100003];
ll depth[100003];
void init(){
    cnt=0;
    memset(head,-1,sizeof(head));
}
void addedge(ll u,ll v,ll id){
    e[cnt].to=v;
    e[cnt].next=head[u];
    e[cnt].id=id;
    head[u]=cnt++;
}
void dfs(ll u,ll fa,ll id){
    pa[u]=fa;
    pid[u]=id;
    depth[u]=depth[fa]+1;
    for(ll i=head[u];~i;i=e[i].next){
        ll v=e[i].to;
        if(v==fa)continue;
        dfs(v,u,e[i].id);
    }
}

struct Dsu{
    ll fa[100003];
    ll cnt[100003][31];
    ll siz[100003];
    void init(ll n){
        for(ll i=1;i<=n;i++){
            fa[i]=i;
            siz[i]=1;
            for(ll j=0;j<31;j++){
                if((1ll<<j)&i)cnt[i][j]=1;
                else cnt[i][j]=0;
            }
        }
    }
    ll getfa(ll u){
        if(u==fa[u])return u;
        return fa[u]=getfa(fa[u]);
    }
    bool check(ll u,ll v){
        u=getfa(u);
        v=getfa(v);
        if(u==v)return true;
        return false;
    }
    void Union(ll u,ll v){
        u=getfa(u);
        v=getfa(v);
        fa[u]=v;
        siz[v]+=siz[u];
        for(ll i=0;i<31;i++)cnt[v][i]+=cnt[u][i];
    }
    ll calc(ll u,ll v,ll w){
        ll ret=0;
        u=getfa(u);
        v=getfa(v);
        for(ll i=0;i<31;i++){
            if((1<<i)&w){
                ret+=one*cnt[u][i]*cnt[v][i]*(1ll<<i);
                ret+=one*(siz[u]-cnt[u][i])*(siz[v]-cnt[v][i])*(1ll<<i);
            }
            else {
                ret+=one*(siz[u]-cnt[u][i])*cnt[v][i]*(1ll<<i);
                ret+=one*cnt[u][i]*(siz[v]-cnt[v][i])*(1ll<<i);
            }
        }
        return ret;
    }
}dsu;
ll T;
ll n,m;
int main(){
    fread(buf,1,30000000,stdin);
    T=read();
    while(T--){
        n=read();
        m=read();
        for(ll i=1;i<=m;i++){
            a[i].u=read();
            a[i].v=read();
            a[i].w=read();
        }
        sort(a+1,a+1+m,cmp);
        dsu.init(n);
        init();
        totb=0,totq=0;
        for(ll i=1;i<=m;i++){
            ll u=a[i].u;
            ll v=a[i].v;
            ll w=a[i].w;
            if(dsu.check(u,v)){
                que[++totq]=(query){u,v,w};
            }
            else {
                b[++totb]=a[i];
                addedge(u,v,totb);
                addedge(v,u,totb);
                dsu.Union(u,v);
            }
        }
        /*cout<<"B:\n";
        for(ll i=1;i<=totb;i++){
            cout<<b[i].u<<' '<<b[i].v<<' '<<b[i].w<<endl;
        }
        cout<<"Q:\n";
        for(ll i=1;i<=totq;i++){
            cout<<que[i].u<<' '<<que[i].v<<' '<<que[i].w<<endl;
        }*/
        dfs(1,0,0);
        for(ll i=1;i<=totq;i++){
            ll u=que[i].u,v=que[i].v,w=que[i].w;
            while(u!=v){
                if(depth[u]>depth[v]){
                    b[pid[u]].w+=w;
                    u=pa[u];
                }
                else {
                    b[pid[v]].w+=w;
                    v=pa[v];
                }
            }
        }
        /*cout<<"B:\n";
        for(ll i=1;i<=totb;i++){
            cout<<b[i].u<<' '<<b[i].v<<' '<<b[i].w<<endl;
        }*/
        dsu.init(n);
        sort(b+1,b+1+totb,cmp);
        ll sum=0;
        for(ll i=1;i<=totb;i++){
            sum+=dsu.calc(b[i].u,b[i].v,b[i].w);
            dsu.Union(b[i].u,b[i].v);
        }
        printf("%llu\n",sum);
    }
}

B
爆搜就完事了。

#include<bits/stdc++.h>
using namespace std;

int t,k,w,n;
char s[20],smax[20],smin[20];
int ansmin,ansmax;

int zhuan(char * x){
    int ans=0;
    for(int i=0; x[i]; i++)
        ans=ans*10+x[i]-'0';
    return ans;
}

void maxdfs(int x, int k){
    if(x==n){
        ansmax=max(ansmax,zhuan(smax));
        return;
    }
    maxdfs(x+1,k);
    if(k)
        for(int i=x+1; i<n; i++){
            swap(smax[x],smax[i]);
            maxdfs(x+1,k-1);
            swap(smax[x],smax[i]);
        }
    return;
}

void mindfs(int x, int k){
    if(x==n){
        ansmin=min(ansmin,zhuan(smin));
        return;
    }
    mindfs(x+1,k);
    if(k)
        for(int i=x+1; i<n; i++){
            if(x==0 && smin[i]=='0') continue;
            swap(smin[x],smin[i]);
            mindfs(x+1,k-1);
            swap(smin[x],smin[i]);
        }
    return;
}

int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%s%d",s,&k);
        n=strlen(s);
        for(int i=0; i<=n; i++){
            smin[i]=smax[i]=s[i];
        }
        ansmax=ansmin=zhuan(s);
        maxdfs(0,k);
        mindfs(0,k);
        printf("%d %d\n",ansmin,ansmax);
    }
    return 0;
}

E
签到。

#include<bits/stdc++.h>
using namespace std;

const double pi=acos(-1);
int m;
double R,x,y,r,d,theta;
double ans;
int t;

double yxdl(double a, double b, double c){
    return acos((a*a+b*b-c*c)/(2*a*b));
}

int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d%lf",&m,&R);
        ans=2.0*pi*R;
        for(int i=0; i<m; i++){
            scanf("%lf%lf%lf",&x,&y,&r);
            d=sqrt(x*x+y*y);
            if(R+r<d || d+r<R) continue;
            theta=yxdl(R,d,r);
            ans-=R*2.0*theta;
            theta=yxdl(r,d,R);
            ans+=r*2.0*theta;
            //cout<<i<<" :"<<ans<<endl;
        }
        printf("%.10lf\n",ans);
    }
}

G
数据随机,加了点灵性剪枝跑了线段树。

#include <bits/stdc++.h>
using namespace std;
typedef unsigned int uint;
const int maxn=100003;
uint w,x,y,z;
uint gao(){
    x^=(x<<11);
    x^=(x>>4);
    x^=(x<<5);
    x^=(x>>14);
    w=x^y^z;
    x=y;
    y=z;
    z=w;
    return z;
}
int T;
int a[maxn];
struct que{
    int l,r,p;
}rec[5000003];
int tot;
int n,m;

int mx[maxn<<2];
int lz[maxn<<2];
void pushup(int u){
    mx[u]=max(mx[2*u],mx[2*u+1]);
}
void pushdown(int u){
    if(lz[u]==0)return;
    lz[2*u]=max(lz[2*u],lz[u]);
    mx[2*u]=max(mx[2*u],lz[u]);
    lz[2*u+1]=max(lz[2*u+1],lz[u]);
    mx[2*u+1]=max(mx[2*u+1],lz[u]);
    lz[u]=0;
}
void build(int u,int l,int r){
    lz[u]=0;
    if(l==r){
        mx[u]=0;
        return ;
    }
    int mid=(l+r)/2;
    build(2*u,l,mid);
    build(2*u+1,mid+1,r);
}
void update(int u,int l,int r,int ql,int qr,int x){
    if(ql>r||qr<l)return;
    if(ql<=l&&r<=qr){
        lz[u]=max(lz[u],x);
        mx[u]=max(mx[u],x);
        return;
    }
    pushdown(u);
    int mid=(l+r)/2;
    update(2*u,l,mid,ql,qr,x);
    update(2*u+1,mid+1,r,ql,qr,x);
    pushup(u);
}
int query(int u,int l,int r,int pos){
    if(pos>r||pos<l)return 0;
    if(l==r)return mx[u];
    pushdown(u);
    int mid=(l+r)/2;
    return max(query(2*u,l,mid,pos),query(2*u+1,mid+1,r,pos));
}

int main(){
    scanf("%d",&T);
    while(T--)
    {
        tot=0;
        scanf("%d%d%u%u%u",&n,&m,&x,&y,&z);
        for(int i=1;i<=m;i++){
            int l=gao()%n+1;
            int r=gao()%n+1;
            int v=gao()%(1<<30);
            //cout<<l<<' '<<r<<' '<<v<<endl;
            if(l>r)swap(l,r);
            if(m<=10000)rec[++tot]=(que){l,r,v};
            else {
                int x=2ll*m*l*(n-r+1)/n/n;
                //cout<<x<<endl;
                if(x<=1000||v>(1ll<<30)*x/1000/(x/1000+1))rec[++tot]=(que){l,r,v};
            }
        }
        build(1,1,n);
        long long ans=0;
        for(int i=1;i<=tot;i++)update(1,1,n,rec[i].l,rec[i].r,rec[i].p);
        for(int i=1;i<=n;i++){
            ans^=1ll*i*query(1,1,n,i);
        }
        printf("%lld\n",ans);
    }
}

H
枚举翻转区间的数字范围dp一下。

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int t,n,ans,ansl,ansr;
char s[N];
int dp1[N][10],dp2[N][10],dp3[N][10],l[N][10];

void init(){
    ans=0;
}

void work(){
    for(int j=0; j<=9; j++)
        dp1[0][j]=dp2[n+1][j]=0;
    for(int i=1; i<=n; i++)
        for(int j=0; j<=9; j++){
            dp1[i][j]=dp1[i-1][j];
            if(s[i]=='0'+j)
                dp1[i][j]++;
            if(j)
                dp1[i][j]=max(dp1[i][j-1],dp1[i][j]);
        }
    for(int i=n; i>=1; i--)
        for(int j=9; j>=0; j--){
            dp2[i][j]=dp2[i+1][j];
            if(s[i]=='0'+j)
                dp2[i][j]++;
            if(j<9)
                dp2[i][j]=max(dp2[i][j+1],dp2[i][j]);
        }
    for(int x=0; x<=9; x++){
        for(int y=x; y<=9; y++){
            for(int j=x; j<=y; j++){
                dp3[0][j]=0;
                l[0][j]=0;
            }
            for(int i=1; i<=n; i++){
                for(int j=y; j>=x; j--){
                    dp3[i][j]=dp3[i-1][j];
                    l[i][j]=l[i-1][j];
                    if(s[i]=='0'+j && j==y && dp1[i-1][x]+1>dp3[i][j]){
                        dp3[i][j]=dp1[i-1][x]+1;
                        l[i][j]=i;
                    }
                    if(s[i]=='0'+j && dp3[i-1][j]+1>dp3[i][j]){
                        dp3[i][j]=dp3[i-1][j]+1;
                        l[i][j]=l[i-1][j];
                    }
                    if(j<y && dp3[i][j+1]>dp3[i][j]){
                        dp3[i][j]=dp3[i][j+1];
                        l[i][j]=l[i][j+1];
                    }
                    if(s[i]=='0'+j && j==x && dp2[i+1][y]+dp3[i][j]>ans){
                        ans=dp2[i+1][y]+dp3[i][j];
                        ansl=l[i][j];
                        ansr=i;
                    }
                    //if(x==2 && y==3)
                    //cout<<i<<" "<<j<<":"<<dp3[i][j]<<endl;
                }
            }

        }
    }
    return;
}

int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d%s",&n,s+1);
        init();
        work();
        printf("%d %d %d\n",ans,ansl,ansr);
    }
    return 0;
}

J
先后缀数组求出每种子串出现的次数,然后huffman树。huffman树可以用两个队列做到 O(n) O ( n ) 。整体 O(n) O ( n )

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char buf[30000003];
int rdp=0;
inline int read(){
    int ret=0;
    while(buf[rdp]>='0'&&buf[rdp]<='9'){
        ret*=10;
        ret+=buf[rdp++]-'0';
    }
    rdp++;
    return ret;
}
#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
const int MAXN = 20000000+100;//n*10
int sa[MAXN];
int Rank[MAXN];
int height[MAXN];
int n;
int s[MAXN];
int wa[MAXN],wb[MAXN],wv[MAXN];
int wws[MAXN];
void sort(int *r,int *a,int *b,int n,int m)
{
    int i;
    for(i=0;i<n;i++) wv[i]=r[a[i]];
    for(i=0;i<m;i++) wws[i]=0;
    for(i=0;i<n;i++) wws[wv[i]]++;
    for(i=1;i<m;i++) wws[i]+=wws[i-1];
    for(i=n-1;i>=0;i--) b[--wws[wv[i]]]=a[i];
    return;
}
int c0(int *r,int a,int b)
{return r[a]==r[b]&&r[a+1]==r[b+1]&&r[a+2]==r[b+2];}
int c12(int k,int *r,int a,int b)
{if(k==2) return r[a]<r[b]||r[a]==r[b]&&c12(1,r,a+1,b+1);
    else return r[a]<r[b]||r[a]==r[b]&&wv[a+1]<wv[b+1];}

void dc3(int *r,int *sa,int n,int m)
{
    int i,j,*rn=r+n,*san=sa+n,ta=0,tb=(n+1)/3,tbc=0,p;
    r[n]=r[n+1]=0;
    for(i=0;i<n;i++) if(i%3!=0) wa[tbc++]=i;
    sort(r+2,wa,wb,tbc,m);
    sort(r+1,wb,wa,tbc,m);
    sort(r,wa,wb,tbc,m);
    for(p=1,rn[F(wb[0])]=0,i=1;i<tbc;i++)
        rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++;
    if(p<tbc) dc3(rn,san,tbc,p);
    else for(i=0;i<tbc;i++) san[rn[i]]=i;
    for(i=0;i<tbc;i++) if(san[i]<tb) wb[ta++]=san[i]*3;
    if(n%3==1) wb[ta++]=n-1;
    sort(r,wb,wa,ta,m);
    for(i=0;i<tbc;i++) wv[wb[i]=G(san[i])]=i;
    for(i=0,j=0,p=0;i<ta && j<tbc;p++)
        sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++];
    for(;i<ta;p++) sa[p]=wa[i++];
    for(;j<tbc;p++) sa[p]=wb[j++];
    return;
}
void calheight(int *r, int *sa, int n)
{
    int i, j, k = 0;
    for (i = 1; i <= n; ++i) Rank[sa[i]] = i;
    for (i = 0; i < n; height[Rank[i++]] = k)
        for (k ? k-- : 0, j = sa[Rank[i] - 1]; r[i + k] == r[j + k]; ++k);
    return;
}

int stk[2000003];
int cnt[2000003];
ll ans[1000003];
int top;

struct node{
    ll x,tim;
};
node que1[2000003];
node que2[2000003];
int head1,head2,tail1,tail2;

void add(ll x,ll tim){
    que2[++tail2]=(node){x,tim};
}

void tryunion(){
    if(head2<tail2&&que2[tail2].x==que2[tail2-1].x){
        que2[tail2-1].tim+=que2[tail2].tim;
        tail2--;
    }
}

ll gao1(){
    ll ret=que1[head1].tim/2*2*que1[head1].x;
    add(que1[head1].x*2,que1[head1].tim/2);
    que1[head1].tim%=2;
    if(que1[head1].tim==0)head1++;
    tryunion();
    return ret;
}

ll gao2(){
    ll ret=que2[head2].tim/2*2*que2[head2].x;
    add(que2[head2].x*2,que2[head2].tim/2);
    que2[head2].tim%=2;
    if(que2[head2].tim==0)head2++;
    tryunion();
    return ret;
}

ll gao11(){
    ll ret=que1[head1].x+que1[head1+1].x;
    ++head1;
    que1[head1].tim--;
    if(que1[head1].tim==0)head1++;
    add(ret,1);
    tryunion();
    return ret;
}

ll gao22(){
    ll ret=que2[head2].x+que2[head2+1].x;
    ++head2;
    que2[head2].tim--;
    if(que2[head2].tim==0)head2++;
    add(ret,1);
    tryunion();
    return ret;
}

ll gao12(){
    ll ret=que1[head1].x+que2[head2].x;
    que1[head1].tim--;
    if(que1[head1].tim==0)head1++;
    que2[head2].tim--;
    if(que2[head2].tim==0)head2++;
    add(ret,1);
    tryunion();
    return ret;
}

void print(){
    printf("debug:\nqueue1:\n");
    for(int i=head1;i<=tail1;i++)printf("%lld %lld\n",que1[i].x,que1[i].tim);
    printf("queue2:\n");
    for(int i=head2;i<=tail2;i++)printf("%lld %lld\n",que2[i].x,que2[i].tim);
}

int main()
{
    /*    n=8;
          s[8]=0;
          s[0]=s[1]=2;
          s[2]=s[3]=s[4]=s[5]=1;
          s[6]=s[7]=3;
          dc3(s,sa,n+1,200);
          calheight(s,sa,n);
          for(int i=0;i<=n;i++){
          printf("%d ", sa[i]);
          }
          printf("\n");
          for(int i=1;i<=n;i++){
          printf("%d ", height[i]);
          }
          printf("\n");*/
    fread(buf,1,30000000,stdin);
    int T;
    T=read();
    while(T--){
        n=read();
        for(int i=0;i<n;i++){
            s[i]=read();
            s[i]++;
            ans[i+1]=0;
        }
        s[n]=0;
        dc3(s,sa,n+1,200);
        calheight(s,sa,n);
        top=0;
        ++top;
        stk[top]=0;
        cnt[top]=1;
        ++top;
        stk[top]=n-sa[1];
        cnt[top]=1;
        for(int i=2;i<=n;i++){
            int len=n-sa[i];
            int cm=height[i];
            int tmp=0;
            while(top>0&&cm<=stk[top]){
                tmp+=cnt[top];
                ans[tmp]+=stk[top]-stk[top-1];
                top--;
            }
            if(top>0)ans[tmp]-=(cm-stk[top]);
            ++top;
            stk[top]=cm;
            cnt[top]=tmp;
            ++top;
            stk[top]=len;
            cnt[top]=1;
        }
        int tmp=0;
        for(int i=top;i>=2;i--){
            tmp+=cnt[i];
            ans[tmp]+=stk[i]-stk[i-1];
        }
        head1=head2=1,tail1=tail2=0;
        for(int i=1;i<=n;i++){
            if(ans[i]!=0)que1[++tail1]=(node){i,ans[i]};
        }
        ll p=0;
        ll q=1ll*n*(n+1)/2;
        if(n==1){
            printf("0\n");
            continue;
        }
        while(1){
            if(head1>tail1&&head2==tail2&&que2[head2].tim==1)break;
            if(head2>tail2||(head1<=tail1&&que1[head1].x<que2[head2].x)){
                if(que1[head1].tim>=2){
                    p+=gao1();
                }
                else {
                    if(head2>tail2||(head1<tail1&&que1[head1+1].x<que2[head2].x)){
                        p+=gao11();
                    }
                    else {
                        p+=gao12();
                    }
                }
            }
            else {
                if(que2[head2].tim>=2){
                    p+=gao2();
                }
                else {
                    if(head1>tail1||(head2<tail2&&que2[head2+1].x<que1[head1].x)){
                        p+=gao22();
                    }
                    else {
                        p+=gao12();
                    }
                }
            }
        }
        ll g=__gcd(p,q);
        p/=g,q/=g;
        if(q==1)printf("%lld\n",p);
        else printf("%lld/%lld\n",p,q);
    }
}

K
这玩意的置换群和正12面体差不多,于是burnside一下。限制条件用类似背包的做法搞一下。模数不是素数就用60p做模数,最后除掉60。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll P;
long long mul(long long x,long long y)
{
    return (x*y-(long long)(x/(long double)P*y+1e-3)*P+P)%P;
}
int n,p;
int a[70];
ll C[70][70];
ll dp[70][70];
int main(){
    //cout<<ans<<endl;
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&p);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        P=1ll*p*60;
        C[0][0]=1;
        C[1][0]=C[1][1]=1;
        for(int i=1;i<=60;i++){
            for(int j=0;j<=i;j++){
                if(j==0||j==i)C[i][j]=1;
                else C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
            }
        }

        ll ans=0;

        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(int i=1;i<=n;i++){
            for(int j=0;j<=60;j++){
                if(j<a[i])continue;
                for(int k=j;k<=60;k++){
                    dp[i][k]=(dp[i][k]+mul(C[k][j],dp[i-1][k-j]))%P;
                }
            }
        }
        ans=(ans+dp[n][60])%P;

        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(int i=1;i<=n;i++){
            for(int j=0;j<=12;j++){
                if(5*j<a[i])continue;
                for(int k=j;k<=12;k++){
                    dp[i][k]=(dp[i][k]+mul(C[k][j],dp[i-1][k-j]))%P;
                }
            }
        }
        ans=(ans+mul(24,dp[n][12]))%P;

        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(int i=1;i<=n;i++){
            for(int j=0;j<=30;j++){
                if(2*j<a[i])continue;
                for(int k=j;k<=30;k++){
                    dp[i][k]=(dp[i][k]+mul(C[k][j],dp[i-1][k-j]))%P;
                }
            }
        }
        ans=(ans+mul(15,dp[n][30]))%P;

        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(int i=1;i<=n;i++){
            for(int j=0;j<=20;j++){
                if(3*j<a[i])continue;
                for(int k=j;k<=20;k++){
                    dp[i][k]=(dp[i][k]+mul(C[k][j],dp[i-1][k-j]))%P;
                }
            }
        }
        ans=(ans+mul(20,dp[n][20]))%P;
        ans=ans/60;
        printf("%lld\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值