• Moscow Pre-Finals Workshop 2020



    Moscow Pre-Finals Workshop 2020 - Legilimens+Coffee Chicken Contest (XX Open Cup, Grand Prix of Nanjing)

    CF GYM 102994

    这场的题目来源主要是19年多校。


    A. Everyone Loves Playing Games(线性基 带悔贪心)

    线性基+带悔贪心,具体我先咕了

    #include <bits/stdc++.h>
    
    #define pb emplace_back
    #define pii pair<int, int>
    #define fir first
    #define sec second
    #define ll long long
    using namespace std;
    
    #define gc() getchar()
    inline int read()
    {
        int now=0,f=1; char c=gc();
        for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
        for(;isdigit(c);now=now*10+c-48,c=gc());
        return now*f;
    }
    
    inline ll readll()
    {
        ll now=0,f=1; char c=gc();
        for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
        for(;isdigit(c);now=now*10+c-48,c=gc());
        return now*f;
    }
    
    const int mod = 1e9+7;
    inline int add(int a,int b){return a+b>=mod? a+b-mod: a+b;}
    inline int sub(int a,int b){return a<b? a-b+mod: a-b;}
    inline int mul(int a,int b){return 1LL*a*b%mod;}
    int qpow(int a,int b){
        int ret=1;
        for(; b; b>>=1){
            if(b&1) ret=mul(ret,a);
            a=mul(a,a);
        }
        return ret;
    }
    inline int rev(int x){return qpow(x,mod-2);}
    
    const int N = 1e4+10;
    const int M = 60;
    struct LB{
        ll b[65];
        void clear(){memset(b,0,sizeof(b));}
        void ins(ll x){
            for(int i=M; i>=0; --i){
                if((x>>i)&1){
                    if(!b[i]) { b[i]=x; return;}
                    x ^= b[i];
                }
            }
        }
    } A, B;
    
    void solve(){
        int n=read(), m=read();
        A.clear(), B.clear();
        ll X = 0;
        for(int i=1; i<=n; i++){
            ll x=readll(), y=readll();
            X ^= x; A.ins(x^y);
        }
        for(int i=1; i<=m; i++){
            ll x=readll(), y=readll();
            X ^= x; B.ins(x^y);
        }
        ll ans=X;
        for(int i=M; i>=0; --i){
            if(!A.b[i] && !B.b[i]) continue;
            if(A.b[i] && B.b[i]){
                if((ans>>i)&1) ans ^= A.b[i];
                A.ins(A.b[i]^B.b[i]);
            } 
            else if(A.b[i]) ans=max(ans, ans^A.b[i]);
            else if(B.b[i]) ans=min(ans, ans^B.b[i]);
        }
        printf("%lld
    ",ans);
    }
    int main(){
        int T=read();
        while(T--) solve();
        return 0;
    }
    

    B. Gifted Composer(二分 Hash)

    (Description)
    初始有一个空字符串,(n)次操作,每次在串的前面或后面加一个字符,求每次操作后字符串的循环节种数。
    (s)的循环节(t)定义为:(s)(k)(t)组成或由(k)(t)(t)的一个前缀组成。
    (nleq 10^6)

    (Solution)
    给定(s)和长度(k),判断(s)是否有上述循环节 等价于 判断是否有(s[1,n-k]==s[k+1,n])。哈希即可(O(1))判断。

    有个性质是:长度为(k)的循环节会在(k)时刻出现,若它在(k+t)时刻消失,则以后不会再出现。
    因为多一个字符导致(k)循环节消失后,再在前面或后面加字符,它也不会再成为循环节。
    所以先对最终串哈希。枚举循环节长度(k),二分它消失的时刻(k+t),使([k,k+t])的答案(+1)即可。

    //655ms	46000KB
    #include <bits/stdc++.h>
    #define pc putchar
    #define gc() getchar()
    #define pb emplace_back
    #define seed 31
    typedef long long LL;
    typedef unsigned long long ull;
    const int N=1e6+6;
    
    int sum[N],L[N],R[N];
    ull hs[N*3],pw[N];
    char s[N*3];
    
    inline int read()
    {
    	int now=0,f=1; char c=gc();
    	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    	for(;isdigit(c);now=now*10+c-48,c=gc());
    	return now*f;
    }
    inline char Get()
    {
    	char c=gc(); while(!isalpha(c)) c=gc();
    	return c;
    }
    inline ull Hash(int l,int r)
    {
    	return hs[r]-hs[l-1]*pw[r-l+1];
    }
    bool Check(int t,int k)
    {
    	return Hash(L[t],R[t]-k)==Hash(L[t]+k,R[t]);
    }
    
    int main()
    {
    	int n=read(),h=1e6+1,t=1e6+1;
    	static char ss[5];
    	for(int i=1; i<=n; ++i)
    	{
    		if(Get()=='a') scanf("%s",ss), s[t++]=ss[0]=='s'?ss[1]:ss[0];
    		else scanf("%s",ss), s[--h]=ss[0]=='s'?ss[1]:ss[0];
    		L[i]=h, R[i]=t-1;
    	}
    
    	pw[0]=1;
    	for(int i=1; i<=n; ++i) pw[i]=pw[i-1]*seed;
    	for(int i=h; i<t; ++i) hs[i]=hs[i-1]*seed+s[i]-'a';
    
    	for(int i=1; i<=n; ++i)
    	{
    		int l=i,r=n,mid;
    		while(l<r)
    			if(Check(mid=l+r+1>>1,i)) l=mid;
    			else r=mid-1;
    		++sum[i], --sum[l+1];
    	}
    	for(int i=1; i<=n; ++i) sum[i]+=sum[i-1], printf("%d
    ",sum[i]);
    
    	return 0;
    }
    

    D. String Theory(后缀数组) √

    做过的题,见这儿

    
    

    G. Blackjack(概率DP 退背包)

    (Description)
    给定(a,b,n)(n)个数。从(n)个数中依次取一个数,直到当前取的数的和(sumgt a)。若此时(sum>b)则输,否则赢。求(n)个数随机排列的情况下赢的概率。
    (n,a,bleq 500)

    (Solution)
    问题在于如何表示任意一种排列,感觉是个套路。
    (f[i][j][k])表示前(i)个数,选了其中(j)个,选的数的和为(k)的概率。则当前排列中含前(i)个数的(j)个数。所以:

    [f[i][j][k]=f[i-1][j][k]+f[i-1][j-1][k-A[i]]*frac{j}{n-(j-1)} ]

    注意要乘(j)!因为不乘(j)还是按顺序取的,不表示所有排列,乘(j)即在运算中乘了(j!),表示取了(j)个数的所有排列的情况。

    注意这是个加法的背包,所以可以退背包,即:

    [f[i-1][j][k]=f[i][j][k]-f[i-1][j-1][k-A[i]]*frac{j}{n-(j-1)} ]

    枚举第(i)个数,令它作为最后选中的数,然后退背包使它的贡献从(f[n])中删去。
    那么(A_i)作为最后选中的数且合法的情况即为:

    [sum_{j=0}^{n-1}sum_{k,k<a&k+A_iin(a,b]}frac{f'[j][k]}{n-j} ]

    注意要除以(n-j)!即当前已选了(j)个限定(i)为最后一个的概率。
    系数的细节也太容易漏了。

    复杂度(O(n^3))

    PS:CF上除法还挺快的... 不需要存(frac1i)的数组变成乘法。

    //358ms	4000KB
    #include <bits/stdc++.h>
    #define pc putchar
    #define gc() getchar()
    #define pb emplace_back
    typedef long long LL;
    const int N=505;
    
    int A[N];
    double f[N][N],g[N][N];
    
    inline int read()
    {
    	int now=0,f=1; char c=gc();
    	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    	for(;isdigit(c);now=now*10+c-48,c=gc());
    	return now*f;
    }
    
    int main()
    {
    	int n=read(),a=read(),b=read();
    	for(int i=1; i<=n; ++i) A[i]=read();
    
    	f[0][0]=1;
    	for(int i=1,sum=0; i<=n; ++i)
    	{
    		sum=std::min(sum+A[i],b);
    		for(int j=i,t=A[i]; j; --j)
    			for(int k=sum; k>=t; --k)
    				f[j][k]+=f[j-1][k-t]*j/(n-j+1);
    	}
    	double ans=0;
    	for(int i=1; i<=n; ++i)
    	{
    		memcpy(g,f,sizeof f);
    		for(int j=1,t=A[i]; j<n; ++j)
    			for(int k=t; k<=b; ++k)
    				g[j][k]-=g[j-1][k-t]*j/(n-j+1);
    		for(int j=0,t=A[i]; j<n; ++j)
    			for(int k=0; k<=a && k+t<=b; ++k)
    				if(k+t>a) ans+=g[j][k]/(n-j);
    	}
    	printf("%.10f
    ",ans);
    
    	return 0;
    }
    

    I. Gaokao √

    找规律题。

    #include <bits/stdc++.h>
    
    #define pb emplace_back
    #define pii pair<int, int>
    #define fir first
    #define sec second
    #define ll long long
    using namespace std;
    
    #define gc() getchar()
    inline int read()
    {
        int now=0,f=1; char c=gc();
        for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
        for(;isdigit(c);now=now*10+c-48,c=gc());
        return now*f;
    }
    
    inline ll readll()
    {
        ll now=0,f=1; char c=gc();
        for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
        for(;isdigit(c);now=now*10+c-48,c=gc());
        return now*f;
    }
    
    const int mod = 1e9+7;
    inline int add(int a,int b){return a+b>=mod? a+b-mod: a+b;}
    inline int sub(int a,int b){return a<b? a-b+mod: a-b;}
    inline int mul(int a,int b){return 1LL*a*b%mod;}
    int qpow(int a,int b){
        int ret=1;
        for(; b; b>>=1){
            if(b&1) ret=mul(ret,a);
            a=mul(a,a);
        }
        return ret;
    }
    inline int rev(int x){return qpow(x,mod-2);}
    
    const int N = 1e3+10;
    int fac[N], ifac[N];
    void init(int n){
        fac[0]=1;for(int i=1; i<=n; i++) fac[i]=mul(fac[i-1], i);
        ifac[n]=rev(fac[n]); for(int i=n-1; i>=0; --i) ifac[i]=mul(ifac[i+1],i+1);
    }
    inline int C(int n,int m){
        return mul(fac[n], mul(ifac[m], ifac[n-m]));
    }
    int f[N][N];
    void print(int x){
        for(int i=7; i>=0; --i) cout<<((x>>i)&1);
    }
    
    ll cal(ll x){
        ll ret=1;
        for(; x; x>>=1) if(x&1) ret<<=1;
        return ret;
    }
    int main(){
        int T=read();
        while(T--){
            printf("%lld
    ",cal(readll()-1));
        }
        return 0;
    }
    

    L. Landlord(DFS) √

    (Description)
    给定无限大平面上的两个矩形,求它们将平面分成几个连通块。

    (Solution)
    对给定的(4)个点离散化,然后直接DFS求连通块数。
    离散化的时候对所得下标乘(2)(+1)得到新下标,再标记(vis=1)会很方便。

    //78ms	0KB
    #include <bits/stdc++.h>
    #define pc putchar
    #define gc() getchar()
    #define pb emplace_back
    typedef long long LL;
    const int N=20,Way[5]={1,0,-1,0,1};
    
    int refx[N],refy[N],vis[N][N];
    struct Point
    {
    	int x1,y1,x2,y2;
    }A[2];
    
    inline int read()
    {
    	int now=0,f=1; char c=gc();
    	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    	for(;isdigit(c);now=now*10+c-48,c=gc());
    	return now*f;
    }
    int Find(int *a,int x,int r)
    {
    	int l=1,mid;
    	while(l<r)
    		if(a[mid=l+r>>1]<x) l=mid+1;
    		else r=mid;
    	return l*2+1;
    }
    void DFS(int x,int y)
    {
    	vis[x][y]=1;
    	for(int i=0; i<4; ++i)
    	{
    		int xn=x+Way[i],yn=y+Way[i+1];
    		if(xn && yn && xn<N && yn<N && !vis[xn][yn]) DFS(xn,yn);
    	}
    }
    
    int main()
    {
    	for(int T=read(); T--; )
    	{
    		for(int i=0; i<2; ++i) A[i]=(Point){read(),read(),read(),read()};
    		int tx=0,ty=0;
    		for(int i=0; i<2; ++i) refx[++tx]=A[i].x1, refx[++tx]=A[i].x2;
    		for(int i=0; i<2; ++i) refy[++ty]=A[i].y1, refy[++ty]=A[i].y2;
    		std::sort(refx+1,refx+1+tx), std::sort(refy+1,refy+1+ty);
    		tx=std::unique(refx+1,refx+1+tx)-refx-1;
    		ty=std::unique(refy+1,refy+1+ty)-refy-1;
    
    		memset(vis,0,sizeof vis);
    		for(int i=0; i<2; ++i)
    		{
    			int l1=Find(refx,A[i].x1,tx),r1=Find(refx,A[i].x2,tx);
    			int l2=Find(refy,A[i].y1,ty),r2=Find(refy,A[i].y2,ty);
    			for(int a=l1; a<=r1; ++a) vis[a][l2]=1, vis[a][r2]=1;
    			for(int b=l2; b<=r2; ++b) vis[l1][b]=1, vis[r1][b]=1;
    		}
    		int res=0;
    		for(int i=1; i<N; ++i)
    			for(int j=1; j<N; ++j)
    				if(!vis[i][j]) ++res, DFS(i,j);
    		printf("%d
    ",res);
    	}
    
    	return 0;
    }
    

    ------------------------------------------------------------------------------------------------------------------------
    无心插柳柳成荫才是美丽
    有哪种美好会来自于刻意
    这一生波澜壮阔或是不惊都没问题
    只愿你能够拥抱那种美丽
    ------------------------------------------------------------------------------------------------------------------------
  • 相关阅读:
    类似吸顶功能解决ios不能实时监听onscroll的触发问题
    js 移动端识别手机号码
    H5输入框实时记录文字个数
    C语言指针和数组
    PHP变量
    PHP 的引用计数基础知识
    PHP提高效率的经验
    JS内置Function对象详解
    Javascript小细节总结
    浅析C++中内存分配的方式
  • 原文地址:https://www.cnblogs.com/SovietPower/p/14617062.html
Copyright © 2020-2023  润新知