HDU校赛 | 2019 Multi-University Training Contest 1

2019 Multi-University Training Contest 1

http://acm.hdu.edu.cn/contests/contest_show.php?cid=848

1001. Blank

这题我打比赛的时候想到正解了没敢写...

\(f_{a,b,c,d}\)表示\(\{0,1,2,3\}​\)最后一次出现的位置排序之后的结果,那么每次枚举四种情况转移就好了。

复杂度\(O(Tn^4)\),由于转移的循环除了个\(4!\)的常数所以跑的很快。

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

void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}

void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

#define lf double

#define pii pair<int,int >
#define vec vector<int >

#define pb push_back
#define mp make_pair
#define fr first
#define sc second

#define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)

const int maxn = 1e6+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 998244353;

int f[2][102][102][102],n,m,ans;
vector<pii > s[102];

void add(int &x,int y) {x+=y;if(x>=mod) x-=mod;}

int check(int a,int b,int c,int d) {
    for(vector<pii > :: iterator i=s[a].begin();i!=s[a].end();i++)
        if((b>=i->fr)+(c>=i->fr)+(d>=i->fr)+1!=i->sc) return 0;
    return 1;
}

void solve() {
    read(n),read(m);
    for(int i=1,l,r,x;i<=m;i++) read(l),read(r),read(x),s[r].pb(mp(l,x));
    f[0][0][0][0]=1;
    for(int a=0,t=0;a<=n;a++,t^=1) {
        for(int b=0;b<=a+1;b++)
            for(int c=0;c<=b;c++)
                for(int d=0;d<=c;d++)
                    f[t^1][b][c][d]=0;
        for(int b=0;b<(a?a:1);b++)
            for(int c=0;c<(b?b:1);c++)
                for(int d=0;d<(c?c:1);d++) {
                    if(!check(a,b,c,d)) continue;
                    add(f[t^1][b][c][d],f[t][b][c][d]);
                    add(f[t^1][a][c][d],f[t][b][c][d]);
                    add(f[t^1][a][b][d],f[t][b][c][d]);
                    add(f[t^1][a][b][c],f[t][b][c][d]);
                    if(a==n) add(ans,f[t][b][c][d]);
                }
    }
    write(ans);
}

void clear() {
    ans=0;
    memset(f,0,sizeof f);
    for(int i=1;i<=n;i++) s[i].clear();
}

int main() {
    int t;read(t);while(t--) solve(),clear();
    return 0;
}

1002. Operation

赛后改的。。

考虑记录前缀线性基,然后我们模仿单调队列,贪心的让每一位的位置尽可能的靠后。

实现的话考虑对线性基每一位记录这一位最前出现的位置,这是因为这一位可能是很多数异或起来的,取最前面那个,实现可以参照代码。

复杂度\(O(Tn\log n)\)

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

void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}

void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

#define lf double

#define pii pair<int,int >
#define vec vector<int >

#define pb push_back
#define mp make_pair
#define fr first
#define sc second

#define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)

const int maxn = 1e6+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 1e9+7;

int v[maxn],n,a[maxn][31],p[maxn][31],m;

void append(int x,int pos) {
    for(int i=30;~i;i--) a[pos][i]=a[pos-1][i],p[pos][i]=p[pos-1][i];
    int pps=pos;
    for(int i=30;~i;i--)
        if(x&(1<<i)) {
            if(!a[pps][i]) {a[pps][i]=x;p[pps][i]=pos;return ;}
            if(pos>p[pps][i]) swap(x,a[pps][i]),swap(pos,p[pps][i]);
            x^=a[pps][i];
        }
}

int query(int l,int r) {
    int ans=0;
    for(int i=30;~i;i--)
        if(p[r][i]>=l&&(ans^a[r][i])>ans) ans^=a[r][i];
    return ans;
}

void solve() {
    read(n),read(m);
    for(int i=1,x;i<=n;i++) read(x),append(x,i);
    int la=0;
    for(int i=1;i<=m;i++) {
        int op,l,r;read(op);
        if(op==0) {
            read(l),read(r);l=(l^la)%n+1,r=(r^la)%n+1;if(l>r) swap(l,r);
            write(la=query(l,r));
        } else {
            read(r);r=r^la;append(r,++n);
        }
    }
}

void clear() {
    for(int i=1;i<=n;i++) {
        memset(a[i],0,sizeof a[i]);
        memset(p[i],0,sizeof p[i]);
    }
}

int main() {
    int t;read(t);while(t--) solve(),clear();
    return 0;
}

1004. Vacation

二分答案,然后从后往前枚举判断就好了。

复杂度\(O(Tn\log v)\)

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

void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}

void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

#define lf double

#define pii pair<int,int >
#define vec vector<int >

#define pb push_back
#define mp make_pair
#define fr first
#define sc second

#define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)

const int maxn = 1e5+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 1e9+7;

int n,l[maxn],s[maxn],v[maxn];

int check(lf t) {
    lf lim=-1e9;
    for(int i=n;~i;i--) {
        lf tmp=(lf)s[i]-(lf)v[i]*t;
        if(tmp>lim) lim=tmp;
        lim+=l[i];
    }//printf("lim :: %.6lf\n",lim);
    return lim-l[0]<=0;
}

void solve() {
    for(int i=0;i<=n;i++) read(l[i]);
    for(int i=0;i<=n;i++) read(s[i]);
    for(int i=0;i<=n;i++) read(v[i]);
    lf l=0,r=1e9;
    while(fabs(r-l)>1e-8) {
        lf mid=(l+r)*0.5;
        if(check(mid)) r=mid;
        else l=mid;
    }printf("%.8lf\n",l);
}

int main() {
    while(scanf("%d",&n)!=EOF) solve();
    return 0;
}

1005. Path

建出最短路径图,求最小割。

代码挖坑。

1012. Sequence

首先我们把\(a\)写成生成函数\(\sum_{i=1}^{n}a_ix^i\)

对于一次\(k\)操作,显然\(a\)的生成函数会乘上\(\sum_{i\geqslant 0}x^{ik}\)

显然顺序不影响答案。

那么统计一下每个操作出现了多少次,答案就是:

\[\left(\sum_{i=1}^{n}a_ix^i\right)\cdot\prod_{k=1}^3\left(\sum_{i\geqslant 0}x^{ik}\right)^{cnt_k} \]

注意到:

\[\left(\sum_{i\geqslant 0}x^{ik}\right)^{t}=\sum_{i\geqslant 0}\binom{i+t-1}{t-1}x^{ik} \]

所以做三遍\(\rm NTT\)就可以了,复杂度\(O(Tn\log n)\)

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

void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}

void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

#define lf double

#define pii pair<int,int >
#define vec vector<int >

#define pb push_back
#define mp make_pair
#define fr first
#define sc second

#define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
#define ll long long 

const int maxn = 1e6+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 998244353;

int n,m,a[maxn],t[4],b[maxn],N,bit,pos[maxn],w[maxn],mxn,fac[maxn],ifac[maxn];

int qpow(int a,int x) {
    int res=1;
    for(;x;x>>=1,a=1ll*a*a%mod) if(x&1) res=1ll*res*a%mod;
    return res;
}

int add(int x,int y) {return x+y>=mod?x+y-mod:x+y;}
int del(int x,int y) {return x-y<0?x-y+mod:x-y;}

void prepare() {
    for(mxn=1,bit=0;mxn<=n*2;mxn<<=1,bit++);N=mxn;
    w[0]=1,w[1]=qpow(3,(mod-1)/mxn),fac[0]=ifac[0]=1;
    for(int i=2;i<=N;i++) w[i]=1ll*w[i-1]*w[1]%mod;
    for(int i=1;i<N;i++) pos[i]=pos[i>>1]>>1|((i&1)<<(bit-1));
    for(int i=1;i<m;i++) fac[i]=1ll*fac[i-1]*i%mod;
    for(int i=1;i<m;i++) ifac[i]=1ll*ifac[i-1]*qpow(i,mod-2)%mod;
}

void ntt(int *r,int op) {
    for(int i=1;i<N;i++) if(pos[i]>i) swap(r[i],r[pos[i]]);
    for(int i=1,d=mxn>>1;i<N;i<<=1,d>>=1)
        for(int j=0;j<N;j+=i<<1)
            for(int k=0;k<i;k++) {
                int x=r[j+k],y=1ll*r[i+j+k]*w[k*d]%mod;
                r[j+k]=add(x,y),r[i+j+k]=del(x,y);
            }
    if(op==-1) {
        reverse(r+1,r+N);int d=qpow(N,mod-2);
        for(int i=0;i<N;i++) r[i]=1ll*r[i]*d%mod;
    }
}

int c(int a,int b) {return 1ll*fac[a]*ifac[b]%mod*ifac[a-b]%mod;}

void calc(int k) {
    for(int i=0;i<N;i++) b[i]=0;
    b[0]=1;
    for(int i=1;i*k<=n;i++) b[i*k]=c(i+t[k]-1,t[k]-1);
    ntt(a,1),ntt(b,1);
    for(int i=0;i<N;i++) a[i]=1ll*a[i]*b[i]%mod;
    ntt(a,-1);
    for(int i=n+1;i<N;i++) a[i]=0;
}

void solve() {
    read(n),read(m);prepare();
    for(int i=1;i<=n;i++) read(a[i]);
    for(int i=1,x;i<=m;i++) read(x),t[x]++;
    for(int i=1;i<=3;i++) calc(i);ll ans=0;
    for(int i=1;i<=n;i++) ans^=1ll*i*a[i];
    printf("%lld\n",ans);
}

void clear() {
    t[1]=t[2]=t[3]=0;
    for(int i=0;i<N;i++) a[i]=b[i]=0;
}

int main() {
    int t;read(t);while(t--) solve(),clear();
    return 0;
}
posted @ 2019-07-30 16:15  Hyscere  阅读(238)  评论(0编辑  收藏  举报