A、牛牛爱字符串
提取全部的数字并且去掉前导0,我是写的python正则表达式re库和int。很方便而且正则用的也比较简单
import re #浓浓的爬虫味... findNumber = re.compile(r'.*?(\d+).*?') while True: try: s = input() list = re.findall(findNumber,s) for item in list: print(int(item), end=' ') print() except: break
B、牛牛爱位运算
选取一些数出来按位与,个数谁你挑
按照与的性质,只有1&1=1,所以你与的越多只会越来越小不可能变大
所以直接找出最大的哪个数就行了
T = int(input()) for _ in range(T): a = list(map(int,input().split()))[1:] print(max(a))
C、牛牛爱博弈
牛牛先手拿石子,牛妹后手,总石子个数给出是n,每次可以拿1,2,4,8,...2^k
问给出的石子总数n,每个人都最优选择下谁会赢得比赛
参考官方题解做法:
观察每次可拿石子在模3下的意义,你会发现1,2,1,2,1,2,1,2...
这样你会发现如果给出的n是3的倍数,每次先手取一个数,后手都可以取一个对应的数,让他模3仍为0,因为先手要么拿1要么拿2,后手一定有对应的数来拿。所以后手一定赢。
那么与之对应如果不是三的倍数,先手一定赢,先手可以拿掉n模3下的余数,让他变成3的倍数,与上方同理了。
T = int(input()) for _ in range(T): n = int(input()) if n % 3 == 0: print('Frame') else: print('Alan')
D、牛妹爱数列
给出长度为n的一组数,1e5的数据范围
每个数都是0或者1,你可以进行两种操作,把下标为x的数取非运算操作,第二种是把1~x下标全部取非运算操作。
问你最少变成全部变成0的操作数是多少?
考虑dp写法dp[i][0/1]代表前i个数都是0/1的最少方法数
那么可以找到状态转移方程
第一种情况: 当前位是0,dp[i][0] = min(dp[i - 1][0], dp[i - 1][1] + 1); //前一位都是0,或者前一位都是1,翻转1-(x-1)一次,次数+1 dp[i][1] = min(dp[i - 1][1] + 1, dp[i - 1][0] + 1); //前i-1个数是1,把i下标取反,前i-1个数都是0,把1-i全部取反 当前位是1,dp[i][1] = min(dp[i - 1][1], dp[i - 1][0] + 1); //与上方相同于此类推 dp[i][0] = min(dp[i - 1][0] + 1, dp[i - 1][1] + 1);
#pragma GCC target("avx,sse2,sse3,sse4,popcnt") #pragma GCC optimize("O2,O3,Ofast,inline,unroll-all-loops,-ffast-math") #include <bits/stdc++.h> using namespace std; #define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0) #define all(__vv__) (__vv__).begin(), (__vv__).end() #define endl "\n" #define pai pair<int, int> #define ms(__x__,__val__) memset(__x__, __val__, sizeof(__x__)) typedef long long ll; typedef unsigned long long ull; typedef long double ld; inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar()) s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; } inline void print(ll x, int op = 10) { if (!x) { putchar('0'); if (op) putchar(op); return; } char F[40]; ll tmp = x > 0 ? x : -x; if (x < 0)putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0)putchar(F[--cnt]); if (op) putchar(op); } inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; } ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans *= a; b >>= 1; a *= a; } return ans; } ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; } inline int lowbit(int x) { return x & (-x); } const int dir[][2] = { {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} }; const int MOD = 1e9 + 7; const int INF = 0x3f3f3f3f; const int N = 1e5 + 7; int dp[N][2], a[N]; int main() { int n = read(); for (int i = 1; i <= n; ++i) a[i] = read(); ms(dp, 0x3f); //可做可不做 dp[0][0] = dp[0][1] = 0; for (int i = 1; i <= n; ++i) { if (a[i] == 0) { dp[i][0] = min(dp[i - 1][0], dp[i - 1][1] + 1); dp[i][1] = min(dp[i - 1][1] + 1, dp[i - 1][0] + 1); } else { dp[i][1] = min(dp[i - 1][1], dp[i - 1][0] + 1); dp[i][0] = min(dp[i - 1][0] + 1, dp[i - 1][1] + 1); } } print(dp[n][0]); return 0; }
E、牛妹游历城市
题目意思挺容易理解,选出两个下标如果值按位与不为0说明有边连,边权为lowbit下按位与,可看题目
坑点可能就在于范围是2^32,int最大只有2^31-1,要么开long long,要么注意unsigned int
那么题目很明确说明了要从1-n最短路,没有负权边,dijkstra几乎成为待考虑的算法。
而且边权链接是在按位与下,那么我们按照按位的操作下去吧32位分隔下同为1的连边在一起。
再跑一遍dijkstra就行了,在dijkstra里面从1开始往后面位连接的点跑,注意跑完一位1之后把这一位去掉。
防止下一个数又跑这一位,重复数据一直往堆里插东西,爆栈了。宝哥np!
#pragma GCC target("avx,sse2,sse3,sse4,popcnt") #pragma GCC optimize("O2,O3,Ofast,inline,unroll-all-loops,-ffast-math") #include <bits/stdc++.h> using namespace std; #define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0) #define all(__vv__) (__vv__).begin(), (__vv__).end() #define endl "\n" #define pai pair<ll, int> #define ms(__x__,__val__) memset(__x__, __val__, sizeof(__x__)) typedef long long ll; typedef unsigned long long ull; typedef long double ld; inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar()) s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; } inline void print(ll x, int op = 10) { if (!x) { putchar('0'); if (op) putchar(op); return; } char F[40]; ll tmp = x > 0 ? x : -x; if (x < 0)putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0)putchar(F[--cnt]); if (op) putchar(op); } inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; } ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans *= a; b >>= 1; a *= a; } return ans; } ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; } inline ll lowbit(ll x) { return x & (-x); } const int dir[][2] = { {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} }; const int MOD = 1e9 + 7; const ll INF = 0x3f3f3f3f3f3f3f3f; const int N = 1e5 + 7; ll a[N], dis[N]; bool vis[N]; vector<int> g[35]; int main() { int T = read(); while (T--) { for (int i = 0; i < 35; ++i) g[i].clear(); int n = read(); for (int i = 1; i <= n; ++i) { a[i] = read(); for (int j = 0; j <= 32; ++j) if (a[i] & (1ll << j)) g[j].push_back(i); } ms(dis, 0x3f), ms(vis, 0); priority_queue<pai, vector<pai>, greater<pai>> pq; pq.push({ 0,1 }); dis[1] = 0; while (pq.size()) { pai u = pq.top(); pq.pop(); if (vis[u.second]) continue; vis[u.second] = true; for (int i = 0; i <= 32; ++i) { if ((a[u.second] & (1ll << i)) == 0) continue; for (int j = 0; j < g[i].size(); ++j) { int v = g[i][j]; if (v == u.second) continue; ll w = lowbit(a[u.second] & a[v]); if (u.first + w < dis[v]) { dis[v] = u.first + w; pq.push({ dis[v],v }); } } g[i].clear(); //看过一次之后就把该位链接的边都看过了,清除加快时间以及防止爆栈 } } if (dis[n] == INF) puts("Impossible"); else print(dis[n]); } return 0; }