2011 Multi-University Training Contest 7 - Host by ECNU

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\n",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\n",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\n",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('\n');}
        }
    }
    return 0;
}
View Code

 

posted @ 2017-04-11 18:49  free-loop  阅读(145)  评论(0编辑  收藏  举报