zoukankan      html  css  js  c++  java
  • 2011 Multi-University Training Contest 7

    AC: F I. rank 40/88.

    开场看了F发现是个简单的DP,随便写了一下WA,,,发现把样例倒着输就过不了了。。。原来是忘了最后的时候开始上课的话可能上不了多久。。。

    想到一个简洁的状态方程,然后以为是单调队列优化,突然发现好像只需要求个最小值就行了。。。改改AC了。。

    看榜发现I过了很多,看了一下就是个同色三角形裸题。。A了然后就没有然后了。。。

    看了一下B。第一感觉KMP,感觉通配符的情况不大好处理。。。没学AC自动机。。。

    C。求多边形的对称轴。。。但是枚举对称轴好像会TLE?不敢写。。。赛后发现数据水暴力也能过?另外标称是后缀数组。。膜。。。

    D。感觉好像是化一化公式应该能看出什么性质?

    H。树形DP? J。dance link?

    B.Wildcard(贪心+hash)

    这题很骚。。就是bzoj 3507的原题。然后唯一不同的是,这题是判断通配符串是否为目标串的子串。。。

    把通配符串两端各加一个*就变成了bzoj 3507...

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi 3.1415926535
    # define eps 1e-4
    # define MOD 1000000007
    # define INF 1000000000
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    inline int Scan() {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=100010;
    //Code begin...
    
    char str[N], ss[N];
    int hs[N], shs[N], xing[55], pos, bg, ed;
    struct Node{int x, len; bool flag;}node[55];
    
    int get_hash(int l, int r){return shs[r]-shs[l-1]*hs[r-l+1];}
    bool check(int be, int L){
        int sum=0;
        FOR(i,1,L) if (node[i].flag) sum+=node[i].x; else sum+=node[i].len;
        if (be+sum>ed+1) return false;
        FOR(i,1,L) {
            if (node[i].flag) be+=node[i].x;
            else {
                if (get_hash(be,be+node[i].len-1)!=node[i].x) return false;
                be+=node[i].len;
            }
        }
        return true;
    }
    bool sol(){
        int num, sum, l, cnt, ll;
        FOR(i,2,pos) {
            if (xing[i]-xing[i-1]<=1) continue;
            sum=num=l=ll=cnt=0;
            FOR(j,xing[i-1]+1,xing[i]-1) {
                if (str[j]=='?') {
                    ++num;
                    if (l) node[++cnt].x=sum, node[cnt].len=l; node[cnt].flag=0, sum=l=0;
                }
                else {
                    sum=sum*MOD+str[j]; ++l;
                    if (num) node[++cnt].x=num, node[cnt].flag=1, num=0;
                }
            }
            if (l) node[++cnt].x=sum, node[cnt].len=l; node[cnt].flag=0, sum=l=0;
            if (num) node[++cnt].x=num, node[cnt].flag=1, num=0;
            while (bg<=ed&&!check(bg,cnt)) ++bg;
            if (!check(bg,cnt)) return false;
            FOR(i,1,cnt) if (node[i].flag) ll+=node[i].x; else ll+=node[i].len;
            bg+=ll;
        }
        return true;
    }
    int main ()
    {
        hs[0]=1; FO(i,1,N) hs[i]=hs[i-1]*MOD;
        while (~scanf("%s%s",ss+1,str+2)) {
            pos=0; bg=1; ed=strlen(ss+1);
            for (int i=1; ss[i]; ++i) shs[i]=shs[i-1]*MOD+ss[i];
            int l=1, r=strlen(str+1);
            str[1]='*'; str[++r]='*';
            int flag=0;
            while (str[l]!='*'&&l<=r&&bg<=ed) {
                if (str[l]=='?'||str[l]==ss[bg]) ++l, ++bg;
                else {flag=1; break;}
            }
            while (str[r]!='*'&&l<=r&&bg<=ed) {
                if (str[r]=='?'||str[r]==ss[ed]) --r, --ed;
                else {flag=1; break;}
            }
            if (flag) {puts("NO"); continue;}
            FOR(i,l,r) if (str[i]=='*') xing[++pos]=i;
            if (pos==0&&bg<=ed) {puts("NO"); continue;}
            puts(sol()?"YES":"NO");
        }
        return 0;
    }
    View Code

    D.Trigonometric Function(数学) 

    这题要放在高中我一定写的出来。。。 

    cos(na)化出来是一堆cos(a)和sin(a),sin(na)也是差不多。由余弦定理有cos(A)=(b^2+c^2-a^2)/(2*a*b).这tm显然是有理数。

    那么只需要判断sinA,sinB,sinC是不是有理数即可。因为sinA=sqrt(1-cosA*cosA).化简这个式子然后就只需要判断一个东西是不是完全平方数就行了。

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi 3.1415926535
    # define eps 1e-4
    # define MOD 1000000007
    # define INF 1000000000
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    inline int Scan() {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=20005;
    //Code begin...
    
    int main ()
    {
        LL a, b, c, n, m, k;
        int T;
        scanf("%d",&T);
        while (T--) {
            scanf("%lld%lld%lld%lld%lld%lld",&a,&b,&c,&n,&m,&k);
            LL A=4*b*b*c*c-(b*b+c*c-a*a)*(b*b+c*c-a*a);
            LL B=4*a*a*c*c-(a*a+c*c-b*b)*(a*a+c*c-b*b);
            LL C=4*a*a*b*b-(a*a+b*b-c*c)*(a*a+b*b-c*c);
            LL a1=(LL)sqrt(A), b1=(LL)sqrt(B), c1=(LL)sqrt(C);
            if (a1*a1==A&&b1*b1==B&&c1*c1==C) puts("YES");
            else puts("NO");
        }
        return 0;
    }
    View Code

    F.Sleeping(DP)

    将第0分钟设置为睡觉,第n+1分钟也设置为睡觉。那么题目就是求选出n个睡觉的时刻。使得它们两两间隔要么为0,要么大于l。

    然后状态dp[i][j]表示前i分钟睡了j次且第i分钟在睡觉时可以浪费的最少技能点。

    那么有dp[i][j]=max(dp[i-1][j-1],dp[i-k][j-1])+a[i],(k>=l+1); 

    最后统计一下睡觉次数>=m浪费的最少技能点就行了。复杂度O(n^2).

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi 3.1415926535
    # define eps 1e-4
    # define MOD 1000000007
    # define INF 1000000000
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    inline int Scan() {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=1005;
    //Code begin...
    
    int a[N], dp[N][N];
    
    int main ()
    {
        int n, m, l;
        while (~scanf("%d%d%d",&n,&m,&l)) {
            int sum=0, ans=INF;
            FOR(i,0,n+2) FOR(j,0,n+2) dp[i][j]=INF;
            FOR(i,1,n) scanf("%d",a+i), sum+=a[i];
            a[n+1]=0; dp[0][1]=0;
            FOR(j,2,n+2) {
                int mi=INF;
                FOR(i,j-1,n+1) {
                    if (i-l-1>=0) mi=min(mi,dp[i-l-1][j-1]);
                    dp[i][j]=min(mi+a[i],dp[i-1][j-1]+a[i]);
                }
            }
            FOR(i,m,n) ans=min(ans,dp[n+1][i+2]);
            printf("%d
    ",sum-ans);
        }
        return 0;
    }
    View Code

    H.Replica Placement(树形DP)

    求满足树上每个点要求的最小代价。可以用树形DP来求出。实际上一个点的副本只与它最近的祖先有关系。那么我们可以从根dfs并记录当前的距离。

    如果距离可以满足点的限制,那么有两种选择,第一种这个点不作为副本,第二种这个点作为副本。但是这样dfs会超时。因为没有保存已经求出的东西。

    令dp[x][y]表示x节点以y节点为副本的最小代价。那么之后就好搞了。

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi acos(-1.0)
    # define eps 1e-3
    # define MOD 1000000007
    # define INF 1000000000
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    int Scan() {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=1205;
    //Code begin...
    
    struct Node{int q, s;}node[N];
    struct Edge{int p, next, w;}edge[N];
    int head[N], cnt=1, root, dp[N][N];
    
    void add_edge(int u, int v, int w){
        edge[cnt].p=v; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt++;
    }
    void init(){mem(head,0); mem(dp,-1); cnt=1;}
    int dfs(int x, int w, int fa){
        if (~dp[x][fa]) return dp[x][fa];
        int res=0;
        for (int i=head[x]; i; i=edge[i].next) {
            int v=edge[i].p;
            if (node[v].q<w+edge[i].w) res+=(dfs(v,0,v)+node[v].s);
            else res+=min(dfs(v,w+edge[i].w,fa),dfs(v,0,v)+node[v].s);
        }
        return dp[x][fa]=res;
    }
    int main ()
    {
        int T, n, fa, s, q, w;
        T=Scan();
        while (T--) {
            init();
            n=Scan();
            FOR(i,1,n) {
                fa=Scan(); node[i].q=Scan(); node[i].s=Scan(); w=Scan();
                if (fa) add_edge(fa,i,w);
                else root=i;
            }
            printf("%d
    ",dfs(root,0,root));
        }
        return 0;
    }
    View Code

    I.Triple(补集思想)

    如果把数字看成点,两个数字如果互质则连一条红边,否则连一条蓝边。那么题目就是问同色三角形有多少个。

    考虑补集。那么就是求非同色三角形的个数。

    对于每个顶点,统计从这个顶点出发的两条边颜色都不一样的种数。然后对于所有顶点的种数/2就是非同色三角形的个数。

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi 3.1415926535
    # define eps 1e-4
    # define MOD 1000000007
    # define INF 1000000000
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    inline int Scan() {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=805;
    //Code begin...
    
    int a[N], num[N];
    
    int gcd(int x, int y){return x==0?y:gcd(y%x,x);}
    int main ()
    {
        int T, n;
        scanf("%d",&T);
        while (T--) {
            mem(num,0);
            scanf("%d",&n);
            LL ans=n*(n-1)*(n-2)/6, res=0;
            FOR(i,1,n) scanf("%d",a+i);
            FOR(i,1,n) FOR(j,i+1,n) if (gcd(a[i],a[j])!=1) ++num[i], ++num[j];
            FOR(i,1,n) res+=num[i]*(n-1-num[i]);
            printf("%lld
    ",ans-res/2);
        }
        return 0;
    }
    View Code

    J.Sudoku(Dancing Links)

    学完之后就是模板题了。求n阶数独的解的存在性,判断下多解就行了。

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi 3.1415926535
    # define eps 1e-4
    # define MOD 1000000007
    # define INF 1000000000
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    inline int Scan() {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=16;
    //Code begin...
    
    const int MaxN=N*N*N+10, MaxM=N*N*4+10, maxnode=MaxN*4+MaxM+10;
    int n, Pn;
    char g[20][20], G[20][20], gg[20][20];
    
    int to_char(int x){return x<10?x+'0':x-10+'A';}
    struct DLX{
        int n, m, size;
        int U[maxnode], D[maxnode], R[maxnode], L[maxnode], Row[maxnode], Col[maxnode];
        int H[MaxN], S[MaxM], ansd, ans[MaxN];
        void init(int _n, int _m){
            n=_n; m=_m;
            FOR(i,0,m) S[i]=0, U[i]=D[i]=i, L[i]=i-1, R[i]=i+1;
            R[m]=0; L[0]=m; size=m;
            FOR(i,1,n) H[i]=-1;
        }
        void Link(int r, int c){
            ++S[Col[++size]=c]; Row[size]=r; D[size]=D[c]; U[D[c]]=size; U[size]=c; D[c]=size;
            if (H[r]<0) H[r]=L[size]=R[size]=size;
            else R[size]=R[H[r]], L[R[H[r]]]=size, L[size]=H[r], R[H[r]]=size;
        }
        void remove(int c){
            L[R[c]]=L[c]; R[L[c]]=R[c];
            for (int i=D[c]; i!=c; i=D[i]) for (int j=R[i]; j!=i; j=R[j]) U[D[j]]=U[j], D[U[j]]=D[j], --S[Col[j]];
        }
        void resume(int c){
            for (int i=U[c]; i!=c; i=U[i]) for (int j=L[i]; j!=i; j=L[j]) ++S[Col[U[D[j]]=D[U[j]]=j]];
            L[R[c]]=R[L[c]]=c;
        }
        int Dance(int d){
            if (R[0]==0) {
                FO(i,0,d) G[(ans[i]-1)/Pn/Pn][(ans[i]-1)/Pn%Pn]=to_char((ans[i]-1)%Pn+1);
                return 1;
            }
            int c=R[0];
            for (int i=R[0]; i!=0; i=R[i]) if (S[i]<S[c]) c=i;
            remove(c);
            int res=0;
            for (int i=D[c]; i!=c; i=D[i]) {
                ans[d]=Row[i];
                for (int j=R[i]; j!=i; j=R[j]) remove(Col[j]);
                res+=Dance(d+1);
                if (res>=2) return 2;
                for (int j=L[i]; j!=i; j=L[j]) resume(Col[j]);
            }
            resume(c);
            return res;
        }
    }dlx;
    void place(int &r, int &c1, int &c2, int &c3, int &c4, int i, int j, int k){
        r=(i*Pn+j)*Pn+k; c1=i*Pn+j+1; c2=Pn*Pn+i*Pn+k;
        c3=Pn*Pn*2+j*Pn+k; c4=Pn*Pn*3+((i/n)*n+(j/n))*Pn+k;
    }
    int main ()
    {
        while (~scanf("%d",&n)) {
            Pn=n*n;
            FO(i,0,Pn) scanf("%s",g[i]);
            dlx.init(Pn*Pn*Pn,Pn*Pn*4);
            int r, c1, c2, c3, c4;
            FO(i,0,Pn) FO(j,0,Pn) FOR(k,1,Pn) if (g[i][j]=='.'||g[i][j]==to_char(k)) {
                place(r,c1,c2,c3,c4,i,j,k);
                dlx.Link(r,c1); dlx.Link(r,c2); dlx.Link(r,c3); dlx.Link(r,c4);
            }
            int ans=dlx.Dance(0);
            if (ans==0) {puts("No Solution"); continue;}
            else if (ans==2) {puts("Multiple Solutions"); continue;}
            int flag=1;
            FO(i,0,Pn) FO(j,0,Pn) gg[i][j]=G[i][j];
            FO(i,0,Pn) {
                FO(j,0,Pn) {
                    if (g[i][j]=='.') continue;
                    char tmp=g[i][j]; g[i][j]='.';
                    dlx.init(Pn*Pn*Pn,Pn*Pn*4);
                    FO(i,0,Pn) FO(j,0,Pn) FOR(k,1,Pn) if (g[i][j]=='.'||g[i][j]==to_char(k)) {
                        place(r,c1,c2,c3,c4,i,j,k);
                        dlx.Link(r,c1); dlx.Link(r,c2); dlx.Link(r,c3); dlx.Link(r,c4);
                    }
                    ans=dlx.Dance(0);
                    g[i][j]=tmp;
                    if (ans==1) {puts("Not Minimal"); flag=0; break;}
                }
                if (!flag) break;
            }
            if (flag) {
                FO(i,0,Pn) {FO(j,0,Pn) putchar(gg[i][j]); putchar('
    ');}
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    nginx用户统计
    mysql用户和授权
    memcache操作
    nginx memcache缓存
    memcached安装启动
    Unity 菜单拓展
    用C#创建XML, XML格式化输出
    解析swf文件头,获取flash的原始尺寸
    kinematic与static刚体不会触发任何接触回调
    git使用
  • 原文地址:https://www.cnblogs.com/lishiyao/p/6694962.html
Copyright © 2011-2022 走看看