zoukankan      html  css  js  c++  java
  • 2021-07-06 集训题解

    完美串

    题目传送门

    Description

    Solution

    可以(不能)发现的是,对于一个长度为 (n)(01) 串,(1) 的个数为 (i) 时的合法 (01) 串在旋转意义下本质相同,然后你只需要构造一个然后判断就好了。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define MAXN 1055
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    template <typename T> void chkmax (T &a,T b){a = max (a,b);}
    template <typename T> void chkmin (T &a,T b){a = min (a,b);}
    
    #define IT vector<int>::iterator
    
    int n;
    char s[MAXN];
    
    void makeit (int ned0,int ned1,vector <int> &S){	
    	if (ned0 == ned1){
    		for (Int i = ned0 + ned1 - 1;~i;-- i) S.push_back (i & 1);
    		return ;
    	}
    	else if (ned0 > ned1){
    		makeit (ned0 - ned1,ned1,S);
    		for (IT it = S.begin();it != S.end();)
    			if (*it) it = S.insert (++ it,0);
    			else ++ it;
    		return ;
    	}
    	else{
    		makeit (ned0,ned1 - ned0,S);
    		for (IT it = S.begin();it != S.end();)
    			if (!*it) it = S.insert (++ it,1);
    			else ++ it;
    		return ;
    	}
    }
    
    bitset <MAXN> S1,S2;
    
    int getit (vector <int>&S){
    	bitset <MAXN> cur,rev;int id = 0;
    	for (IT it = S.begin();it != S.end();cur[id ++] = *it ++);
    	rev = cur;int tmp = 0;
    	do{
    		tmp += (S2 & (S1 ^ cur)).none();
    		cur[n] = cur[0],cur >>= 1;
    	}while (cur != rev);
    	return tmp;
    }
    
    signed main(){
        freopen ("A.in","r",stdin);
        freopen ("A.out","w",stdout);
        int cnt0 = 0,cnt1 = 0;
        read (n),scanf ("%s",s);
        for (Int i = 0;i < n;++ i) if (s[i] != '?') S1[i] = (s[i] == '1'),S2[i] = 1,cnt0 += (s[i] == '0'),cnt1 += (s[i] == '1');
        if (cnt0 == n || cnt1 == n) return puts ("1") & 0;
        else{
        	int ans = (cnt1 == 0) + (cnt0 == 0);
        	for (Int i = max(1,cnt1);i <= min (n - 1,n - cnt0);++ i){
        		vector <int> S;
        		makeit (n - i,i,S);
        		ans += getit (S);
        	}
        	write (ans),putchar ('
    ');
        }
     	return 0;
    }
    

    行列式

    题目传送门

    Description

    Solution

    不难想到,假设矩阵为 (A),你可以展开成 (det(A)=det(B+C))(B) 里面全是 (x),这个就相当于构造新矩阵,每一行从 (B,C) 中选一行的矩阵行列式之和。那么可以想到的是,(B) 最多只能选一行,否则交换两行就可以抵消掉了。

    然后你发现 (p_i<i),暗示了构成了一棵树,然后你发现真的是一棵树,如果不选 (x) 的行的话,就相当于能选自环、二元环,如果要选,就相当于可以选一个链出来然后连一条 (x) 的边,正负只需要判断偶环个数即可。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define mod 1000000007
    #define int long long
    #define MAXN 1000005
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    template <typename T> void chkmax (T &a,T b){a = max (a,b);}
    template <typename T> void chkmin (T &a,T b){a = min (a,b);}
    
    int mul (int a,int b){return 1ll * a * b % mod;}
    int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
    int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
    int qkpow (int a,int b){
    	int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
    	return res;
    }
    int inv (int x){return qkpow (x,mod - 2);}
    void Add (int &a,int b){a = add (a,b);}
    void Sub (int &a,int b){a = dec (a,b);}
    
    vector <int> g[MAXN];
    int f[MAXN][6][2],h[MAXN][3][2];
    int n,X,ans,d[MAXN],p[MAXN],b[MAXN],c[MAXN];
    
    void dfs (int u){
    	f[u][0][0] = d[u],f[u][1][0] = f[u][3][1] = mod - c[u],f[u][5][1] = mod - b[u],f[u][0][1] = X,h[u][0][0] = h[u][1][1] = h[u][2][1] = 1;
    	for (Int v : g[u]){
    		dfs (v);
    		int tmp[6][2] = {};
    		//合并二元环的情况
    		for (Int k1 = 0;k1 < 2;++ k1)
    			for (Int k2 = 0;k2 < 2;++ k2)
    				if (!(k1 & k2)) 
    					Add (tmp[2][k1 | k2],mul (h[u][0][k1],mul (b[v],f[v][1][k2]))),
    					Add (tmp[2][k1 | k2],mul (f[u][2][k1],add (f[v][0][k2],add (f[v][2][k2],f[v][4][k2]))));
    		//u选自环的情况
    		for (Int k1 = 0;k1 < 2;++ k1)
    			for (Int k2 = 0;k2 < 2;++ k2)
    				if (!(k1 & k2)) 
    					Add (tmp[0][k1 | k2],mul (f[u][0][k1],add (f[v][0][k2],add (f[v][2][k2],f[v][4][k2]))));
    		//u开始二元环
    		for (Int k1 = 0;k1 < 2;++ k1)
    			for (Int k2 = 0;k2 < 2;++ k2)
    				if (!(k1 & k2)) 
    					Add (tmp[1][k1 | k2],mul (f[u][1][k1],add (f[v][0][k2],add (f[v][2][k2],f[v][4][k2]))));
    		//u合并两个链
    //		cout << "rnmd " << h[u][1][1] << " " << X << " " << f[v][5][1] << endl;
    //		cout << "rnmd " << h[u][2][1] << " " << X << " " << f[v][3][1] << endl;
    		Add (tmp[4][1],mul (X,mul (h[u][1][1],f[v][5][1]))),
    		Add (tmp[4][1],mul (X,mul (h[u][2][1],f[v][3][1])));
    //		cout << tmp[4][1] << endl;
    //		cout << f[u][4][1] << " " << add (f[v][0][0],add (f[v][2][0],f[v][4][0])) << endl;
    		Add (tmp[4][1],mul (f[u][4][1],add (f[v][0][0],add (f[v][2][0],f[v][4][0]))));
    		//u开始链/继续v之外的儿子的链
    		Add (tmp[3][1],mul (f[u][3][1],add (f[v][0][0],add (f[v][2][0],f[v][4][0])))),
    		Add (tmp[5][1],mul (f[u][5][1],add (f[v][0][0],add (f[v][2][0],f[v][4][0]))));
    		//u继续v的链
    		Add (tmp[3][1],mul (h[u][0][0],mul (mod - c[u],f[v][3][1]))),
    		Add (tmp[5][1],mul (h[u][0][0],mul (mod - b[u],f[v][5][1])));
    		//u到子树内一个点的直上直下
    		memcpy (f[u],tmp,sizeof (f[u]));
    		int htmp[3][2] = {};
    		for (Int k1 = 0;k1 < 2;++ k1)
    			for (Int k2 = 0;k2 < 2;++ k2)
    				if (!(k1 & k2))
    					Add (htmp[1][k1 | k2],mul (h[u][0][k1],f[v][3][k2])),
    					Add (htmp[2][k1 | k2],mul (h[u][0][k1],f[v][5][k2])),
    					Add (htmp[1][k1 | k2],mul (h[u][1][k1],add (f[v][0][k2],add (f[v][2][k2],f[v][4][k2])))),
    					Add (htmp[2][k1 | k2],mul (h[u][2][k1],add (f[v][0][k2],add (f[v][2][k2],f[v][4][k2])))),
    					Add (htmp[0][k1 | k2],mul (h[u][0][k1],add (f[v][0][k2],add (f[v][2][k2],f[v][4][k2]))));
     		memcpy (h[u],htmp,sizeof (htmp));
    	}
    }
    
    signed main(){   
    	freopen ("B.in","r",stdin);
        freopen ("B.out","w",stdout);
    	read (n,X);
    	for (Int i = 1;i <= n;++ i) read (d[i]),Sub (d[i],X);
    	for (Int i = 2;i <= n;++ i) read (p[i],b[i],c[i]),Sub (b[i],X),Sub (c[i],X);
    	for (Int i = 2;i <= n;++ i) g[p[i]].push_back (i);
    	dfs (1);int ans = 0;
    	for (Int i = 0;i < 5;i += 2)
    		for (Int k = 0;k < 2;++ k) Add (ans,f[1][i][k]);
    	write (ans),putchar ('
    ');
     	return 0;
    }
    

    取石子游戏

    题目传送门

    Description

    Solution

    可以看出的是,将一堆石子表示为 ((n,a,b)),其中 (n) 表示石子个数,(a) 表示 Alice 可以选的个数,(b) 表示 Bob 可以选的个数。可以发现 ((n\%(a+b),a,b))((n,a,b)) 等价。

    我们设 (A_i) 表示第 (i) 堆石子若 Alice 拿会产生的贡献次数,(B_i) 表示第 (i) 堆石子若 Bob 拿会产生的贡献次数,若 (max(a,b)>nge min(a,b)),那么只有一方可以拿到,这个可以直接储存下来,否则若 (nge max(a,b)),那么谁先拿,你就可以霸占这一堆石子的贡献。

    假如你是 Alice,你一定会想要 (sum A_{p_i}-SB+sum_ B_{p_i}),其中 (p_i) 表示 Alice 霸占的堆数。Bob 也同理。也就是说它们一定会按着 (A_i+B_i) 的顺序交替选,这个用权值线段树处理就好了。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define int long long
    #define MAXN 100005
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    template <typename T> void chkmax (T &a,T b){a = max (a,b);}
    template <typename T> void chkmin (T &a,T b){a = min (a,b);}
    
    #define LOGN 31
    #define ls(x) son[x][0]
    #define rs(x) son[x][1]
    
    int n,rt,tot,cnt[MAXN * LOGN],rig[MAXN * LOGN][2],son[MAXN * LOGN][2];
    
    void pushup (int x){
    	cnt[x] = cnt[ls(x)] + cnt[rs(x)];
    	rig[x][0] = rig[rs(x)][0] + rig[ls(x)][0 ^ cnt[rs(x)] & 1];
    	rig[x][1] = rig[rs(x)][1] + rig[ls(x)][1 ^ cnt[rs(x)] & 1];	
    }
    
    void modify (int &x,int l,int r,int pos){
    	if (!x) x = ++ tot;
    	if (l == r){
    		cnt[x] ++,rig[x][0] = cnt[x] / 2 * l,rig[x][1] = (cnt[x] + 1) / 2 * l;
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	if (pos <= mid) modify (ls(x),l,mid,pos);
    	else modify (rs(x),mid + 1,r,pos);
    	pushup (x);
    }
    
    void Solveit(){
    	read (n);int res = 0;
    	for (Int i = 1;i <= n;++ i){
    		int X,A,B;
    		read (X,A,B),X %= (A + B);
    		int mn = min (A,B),mx = max (A,B);
    		if (mn <= X && X < mx){
    			if (A <= X) res += X / A;
    			else res -= X / B;
    		}
    		else if (mx <= X) res += X / A,modify (rt,1,2e9,X / A + X / B);
    		bool Ali = res - rig[rt][0] > 0,Bob = res - rig[rt][1] < 0;
    		if (Ali && Bob) puts ("First");
    		else if (!Ali && !Bob) puts ("Second");
    		else if (Ali && !Bob) puts ("Alice");
    		else puts ("Bob");
    	}
    }
    
    signed main(){
    	freopen ("C.in","r",stdin);
    	freopen ("C.out","w",stdout);
    	Solveit();
     	return 0;
    }
    
  • 相关阅读:
    Mysql练习#1-建表
    Mysql学习笔记#7-范式
    Git学习笔记#9-标签
    Git学习笔记#8-操作冲突
    Git学习笔记#7-分支操作
    Git学习笔记#6-远程仓库(GitHub)
    Git学习笔记#5-文件删除
    Git学习笔记#4-版本回退
    Git学习笔记#3-修改文件与撤销
    免费分享老男孩全栈9期视频,共126天
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/14983747.html
Copyright © 2011-2022 走看看