• CCPC Finals 2021 (A F G J L)


    CCPC Finals 2021 (A F G J L)

    Problem - A - Codeforces

    A. Mash(模拟)

    思路:由于需要执行的指令条数 k 是有限的 , 考虑直接用队列模拟即可。

    时间复杂度 O ( n + k ) 时间复杂度O(n + k) 时间复杂度O(n+k)

    #include
    using namespace std;
    #define fi first
    #define se second
    #define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    #define int long long
    const int INF = 9e18;
    const int N = 2e6 + 10;
    const int mod = 1e9 + 7;
    typedef pair<int,int>PII;
    
    struct node{
    	string op;
    	char c;
    	int cnt;
    }a[N];
    
    int n , cnt;
    string ans;
    
    signed main(){
    
    	cin >> n >> cnt;
    	
    	queue<node>q;
    	
    	for(int i = 1 ; i <= n ; i ++) {
    		string s;
    		char c;
    		int x = 0;
    		cin >> s;
    		if(s[0] == 'e') {
    			a[i].op = "echo";
    			cin >> c;
    			a[i].c = c;
    		} else {
    			a[i].op = "cp";
    			cin >> x;
    			a[i].cnt = x;
    		}
    		if(cnt) q.push(a[i]);
    		cnt -= 1;
    	}
    	
    	while(cnt) {
    		
    		if(q.size() == 0) break;
    		node now = q.front();q.pop();
    		
    		if(now.op == "echo") {
    			ans += now.c;
    		} else {
    			for(int i = 1 ; i <= now.cnt && cnt ; i ++) {
    				q.push(a[i]);
    				cnt -= 1;
    			}
    		}
    	
    	}
    	
    	
    	while(q.size()) {
    		node now = q.front();q.pop();
    		if(now.op == "echo") {
    			ans += now.c;
    		}
    	}
    	
    	cout << ans << "\n";
    
    	return 0;
    }
    //freopen("文件名.in","r",stdin);
    //freopen("文件名.out","w",stdout);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    F. Modulo(枚举)

    思路:考虑取模运算 , 对比自己大的数取模是没有意义的 , 对数列排序后 , 考虑每次选择比自己小的数作为模数 , 搜索即可 。这样操作当前的数存在单调性 , 所以不会选到两个相同的数。

    #include
    using namespace std;
    #define fi first
    #define se second
    #define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    #define int long long
    const int INF = 9e18;
    const int N = 2e6 + 10;
    const int mod = 1e9 + 7;
    typedef pair<int,int>PII;
    
    int n , a[N] , x , res = -INF;
    
    void dfs(int x){
    	int pos = upper_bound(a + 1 , a + 1 + n , x) - a - 1;
    	if(pos == 0) {
    		res = max(res , x);
    		return ;
    	} else {
    		for(int i = 1 ; i <= pos ; i ++) {
    			dfs(x % a[i]);
    		}
    	}
    }
    
    signed main(){
    
    	cin >> n;
    	for(int i = 1 ; i <= n ; i ++) {
    		cin >> a[i];
    	}
    	cin >> x;
    	sort(a + 1 , a + 1 + n);
    	dfs(x);
    	cout << res << "\n";	
    	
    	return 0;
    }
    //freopen("文件名.in","r",stdin);
    //freopen("文件名.out","w",stdout);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    G. Integer Game(SG打表 ,博弈论)

    思路:考虑各个游戏之间都是独立的 , 计算每一个游戏的 SG 值 , 根据 SG 定理去求先手胜负情况。 对于每一个独立游戏的SG值考虑打表。

    打表函数:

    #include
    using namespace std;
    #define fi first
    #define se second
    #define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    #define int long long
    const int INF = 9e9;
    const int N = 2e6 + 10;
    const int mod = 1e9 + 7;
    typedef pair<int,int>PII;
    
    int l , r , p;
    
    int dp[100][100][100];
    
    int get(int l , int r , int p) {
    	
    	//异或值有含义注意这里什么都不写!!!!
    	if(dp[l][r][p] != -1) return dp[l][r][p];
    	int pos = (r - 1) / p + 1;
    	set<int>st;
    	for(int i = max(pos , l) ; i <= r ; i ++) {
    		st.insert(get(l , i - 1 , p));
    	}
    	for(int i = 0 ; ; i ++) if(!st.count(i)) return dp[l][r][p] = i;
    }
    
    signed main(){
    
    	
    	memset(dp , -1 , sizeof(dp));
    	
    	for(int p = 1 ; p <= 20 ; p ++){
    		cout << "P = " << p << "\n";
    		for(int i = 1 ; i <= 5 ; i ++) {
    			cout << "L = " << i << "\n";
    			cout << "pos:";
    //			for(int j = i , k = 1 ; j <= 30 ; j ++ , k += 1) {
    //				cout << setw(3) << k;
    //			}//未偏移
    			for(int j = i ; j <= 30 ; j ++ ) {
    				cout << setw(3) << j;
    			}//偏移
    			cout << "\n";
    			cout << "val:";
    			for(int j = i ; j <= 30 ; j ++) {
    				cout << setw(3) << get(i , j , p);
    			}
    			cout << "\n\n";
    		}
    	}
    
    	return 0;
    }
    //freopen("文件名.in","r",stdin);
    //freopen("文件名.out","w",stdout);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    规律就是 , 固定 P , L 之后 , 每个相同的 SG 值的位置(R)之间有一个

    R i = R i − 1 ∗ p + ( p + 1 ) R_i=R_{i-1}*p+(p+1) Ri=Ri1p+(p+1)

    的关系 , 对于给出的一个右端点 , 考虑跳到SG值相同的最小位置处 , 显然每一个SG值第一次出现的位置和值之前有一个很明显的关系 , 根据关系把位置坐标对应到SG值即可。

    时间复杂度 O ( n l o g r ) 时间复杂度O(nlogr) 时间复杂度O(nlogr)

    #include
    using namespace std;
    #define fi first
    #define se second
    #define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    #define int long long
    const int INF = 9e18;
    const int N = 2e6 + 10;
    const int mod = 1e9 + 7;
    typedef pair<int,int>PII;
    
    /*
    *p + (p + 1)
    5 5 1
    */
    
    int get(int l , int r , int p) {
    	
    	while((r - (p + 1)) % p == 0 && (r - (p + 1)) / p >= l) r = (r - (p + 1)) / p;
    	r -= (l - 1);
    	int rd = l * (p - 1) + 2;
    	if(r <= rd) {
    		if(r == rd) {
    			return 0;
    		} else {
    			return r;
    		}
    	} else {
    		int cnt = (r - rd - 1) / p + 1;
    		return r - cnt;
    	}
    }
    
    int t , l , r , n , p;
    
    signed main(){
    
    	IOS
    	cin >> t;
    
    	while(t --) {
    		
    		cin >> n >> p;
    		int ok = 0;
    		for(int i = 1 ; i <= n ; i ++) {
    			cin >> l >> r;
    			ok ^= get(l , r , p);
    		}
    		
    		if(ok == 0) {
    			cout << "Second\n";
    		} else {
    			cout << "First\n";
    		}
    		
    	}
    	return 0;
    }
    //freopen("文件名.in","r",stdin);
    //freopen("文件名.out","w",stdout);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    J. jwfw.harie.edu(折半搜索)

    思路:考虑最暴力的做法 , 即枚举所有可能的情况 , 然后和所有的条件比较

    复杂度 O ( 4 10 ∗ n ∗ 10 ) 复杂度O(4^{10}*n*10) 复杂度O(410n10)

    这个复杂度显然不能接受 , 考虑优化 , 折半搜索。即枚举出前五个字母 , 记录每一个状态对应的后五个应该有的状态 ,然后再枚举后五个的状态 , 计数即可。

    由于状态是一个序列 , 需要哈希一下 , 双哈希 , 单哈希会被卡掉

    复杂度 O ( 4 5 ∗ ( 5 n + n + l o g ( 4 5 ) ) ) 复杂度O(4^{5}*(5n+n+log(4^5))) 复杂度O(45(5n+n+log(45)))

    log 是 map 的复杂度 , n 是哈希的复杂度 , 5n 是计算状态的复杂度。

    #include
    using namespace std;
    #define fi first
    #define se second
    #define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    #define int long long
    const int INF = 9e18;
    const int N = 2e4 + 10;
    const int mod = 1e9 + 7;
    typedef pair<int,int>PII;
    
    string s[1500];
    int cnt , t , n;
    int need[N];
    
    //--------------------------------------------------------------------------------
    const int mod1 = 1e9 + 7;
    const int mod2 = 1e9 + 9;
    const int Base1 = 131;
    const int Base2 = 13331;
    int base1[N] , h1[N] , base2[N] , h2[N];
    
    inline void init_hash(int n){
    	base1[0] = base2[0] = 1;
    	for(int i = 1 ; i <= n ; i ++) base1[i] = base1[i - 1] * Base1 % mod1;
    	for(int i = 1 ; i <= n ; i ++) base2[i] = base2[i - 1] * Base2 % mod2; 
    }
    
    inline PII get(int n){
    	
    	h1[0] = h2[0] = 0;
    	for(int i = 1 ; i <= n ; i ++) h1[i] = (h1[i - 1] * Base1 % mod1 + need[i - 1]) % mod1;
    	for(int i = 1 ; i <= n ; i ++) h2[i] = (h2[i - 1] * Base2 % mod2 + need[i - 1]) % mod2;
    	int x = ((h1[n] - h1[0] * base1[n]) % mod1 + mod1) % mod1;
    	int y = ((h2[n] - h2[0] * base2[n]) % mod2 + mod2) % mod2;
    	return {x , y};
    }
    //--------------------------------------------------------------------------------
    
    void dfs(int x , string s_now){
    	
    	if(x == 5) {
    		s[++cnt] = s_now;
    		return ;
    	}
    	for(char i = 'A' ; i <= 'D' ; i ++) {
    		dfs(x + 1 , s_now + i);
    	}
    }
    
    signed main(){
    
    	IOS
    	dfs(0 , "");
    	init_hash(N - 10);
    	cin >> t;
    	
    	while(t --) {
    		
    		cin >> n;
    		int res = 0;
    		map<pair<int , int> , int> mp;
    		vector<pair<string , int>>ve;
    		for(int i = 1 ; i <= n ; i ++) {
    			string s;int x;
    			cin >> s >> x;
    			ve.push_back({s , x / 10});
    		}
    		
    		//第一半搜索
    		for(int i = 1 ; i <= cnt ; i ++) {
    			
    			string now = s[i];
    			bool ok = 1;
    			
    			for(int j = 0 ; j < n ; j ++) {
    				string s = ve[j].first;
    				int num = ve[j].second;
    				int cnt = 0;
    				for(int k = 0 ; k < 5 ; k ++) {
    					if(s[k] == now[k]) cnt += 1;
    				}
    				if(cnt > num) {
    					ok = 0;
    					break;
    				} else {
    					need[j] = num - cnt;
    				}
    			}
    			if(!ok) continue;
    			PII val = get(n); 
    			mp[val] += 1;
    		}	
    		
    		//第二半搜索
    		for(int i = 1 ; i <= cnt ; i ++) {
    			
    			string now = s[i];
    			
    			for(int j = 0 ; j < n ; j ++) {
    				string s = ve[j].first;
    				int num = ve[j].second;
    				int cnt = 0;
    				for(int k = 5 ; k < 10 ; k ++) {
    					if(s[k] == now[k - 5]) cnt += 1;
    				}
    				need[j] = cnt;
    			}
    			PII val = get(n); 
    			if(mp.find(val) != mp.end()) res += mp[val];
    		}	
    		
    		cout << res << "\n";
    		
    	}
    	
    
    	return 0;
    }
    //freopen("文件名.in","r",stdin);
    //freopen("文件名.out","w",stdout);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121

    L. Paid Leave (贪心)

    思路:对于每一个需要填充的区间 , 考虑贪心填充 , 最小化贡献 。 需要注意的是 , 每一个区间的 y 不变 , 但是 x 是会被前一个区间影响的 , 动态更新即可。

    #include
    using namespace std;
    #define fi first
    #define se second
    #define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    #define int long long
    const int INF = 9e18;
    const int N = 2e6 + 10;
    const int mod = 1e9 + 7;
    typedef pair<int,int>PII;
    
    int n , m , x , y;
    int pos[N] , dis[N];
    
    signed main(){
    
    	cin >> n >> m >> x >> y;
    	
    	for(int i = 1 ; i <= m ; i ++) {
    		cin >> pos[i];
    		dis[i] = pos[i] - pos[i - 1] - 1;
    	}
    	m += 1;
    	dis[m] = (n + 1) - pos[m - 1] - 1;
    	
    	int need = y + 2;
    	int res = 0 , l = 0 , pre = 0;
    	
    	for(int i = 1 ; i <= m ; i ++) {
    		l = min(x , y - pre);
    		int cnt = dis[i] / need;
    		int oth = dis[i] % need;
    		res += cnt * 2;
    		if(oth > l) {
    			res += 1;
    			pre = oth - (l + 1);
    		} else {
    			pre = oth;
    		}
    	}
    	
    	cout << res << "\n";
    
    	return 0;
    }
    //freopen("文件名.in","r",stdin);
    //freopen("文件名.out","w",stdout);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
  • 相关阅读:
    【案例分享】IPSec VPN与NQA联动实现主备对等体和主备链路快速切换
    计算机毕业设计SSM毕业设计管理系统【附源码数据库】
    每天一个注解之 @WebMethod
    详解 React 18 更新后的特性,一文即懂
    02_udp编程
    tx.origin 与 msg.sender
    Docker学习2——Docker高级
    Java基础之ArrayList集合(最简单最详细)
    windows任务栏卡死,重启也没用
    自定义MVC原理
  • 原文地址:https://blog.csdn.net/woshilichunyang/article/details/133870091