近几个月来的第一次组队训练,结果不满意,毕竟很久没有组队打比赛了,可能状态还要慢慢调整,我相信会越来越好的。
赛时只过了3题,我背锅。签到题F给了队友一个假做法,然后又不知道自己错在哪,浪费了很多时间在想为什么自己的做法不对。最后无脑暴力过了。比赛时候不能犯这种错误,即使给了假做法明知不对就尽快想正解,不要纠结于一个假做法,赛后再去慢慢想,不浪费比赛时间。
部分题解:
F题:
题意:一长为n的字符串,能得到n个前缀字符串,需要将前缀字符串中的每个字符转换成在当前的前缀字符串中该字符最后一次出现的位置后面不同的字符的数量所对应的字符,求这n个转换后的前缀字符串中字典序最大的。
做法:暴力枚举每个前缀转化得到的字符串,并记录下来,排序输出最大的。
代码:
#include <cmath> #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <queue> #include <map> #include <vector> #include <string> #include <set> #include <sstream> #include <stack> #include <deque> //#include <bits/stdc++.h using namespace std; #define INF 0x3f3f3f3f #define int long long #define ll long long #define endl '\n' #define null NULL #define ls p<<1 #define rs p<<1|1 #define fi first #define se second #define mp make_pair #define pb push_back #define vi vector<int> #define mii map<int,int> #define pii pair<int,int> #define ull unsigned long long #define pqi priority_queue<int> #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define ct cerr<<"Time elapsed:"<<1.0*clock()/CLOCKS_PER_SEC<<"s.\n"; #define ull unsigned long long #define rep(i,a,b) for(int i=(a);i<=(b);i++) inline int rd() {//读入优化,可以加快数字的输入 char p = 0; int r = 0, o = 0; for (; p < '0' || p>'9'; o |= p == '-', p = getchar()); for (; p >= '0' && p <= '9'; r = (r << 1) + (r << 3) + (p ^ 48), p = getchar()); return o ? (~r) + 1 : r; } void write(int x) { if (x < 0) putchar('-'), x = -x; if (x > 9) write(x / 10); putchar(x % 10 + '0'); } const int M = 2e5 + 10; const int mod=1e9+7; const double pi=acos(-1.0); int qpow(int a,int b){ int result=1; int s=a; while(b){ if(b&1){ result=(result*a)%mod; } a=(a*a)%mod; b/=2; } return result; } int gcd(int a,int b){ if(b==0) return a; else{ return gcd(b,a%b); } } string s; int bm[2009]; vector<string>ans; void solve() { int n; cin>>n; cin>>s; int mx=0; int k=0; for(int q=0;q<n;q++){ memset(bm,0,sizeof(bm)); for(int i=0;i<=q;i++){ // if(bm[s[i]]!=0) continue; int su=0; bool vs[2008]; memset(vs,0,sizeof(vs)); for(int j=q;j>=i;j--) { if(s[j]!=s[i]){ if(vs[s[j]]==0){ su++; vs[s[j]]=1; }} else{ bm[s[i]]=su; break; } } } string s1; s1=""; for(int i=0;i<=q;i++){ s1+=('a'+bm[s[i]]); } // cout<<q<<"sda"<<s1<<"\n"; ans.push_back(s1); } sort(ans.begin(),ans.end()); cout<<ans.back()<<"\n"; } signed main() { int t; // cin>>t; t=1; while(t--){ solve(); } }
B题:
题意:一个含有n个元素的数组,给出m条要求。每条包含u,v,w三个数字,代表au^av=w。构造满足条件的数组,输出最小的和。
做法:bfs,状态压缩,枚举每个二进制位,如果该位异或和为一,则au与av该位相反。
代码:
#include <iostream> #include <set> #include <queue> #include <bits/stdc++.h> using namespace std; #define ll long long #define int long long const int mod = 998244353; ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) { ans = ans * a; } a = a * a; b >>= 1; } return ans; } ll gcd(ll a, ll b) { // 求最大公因数 return b == 0 ? a : gcd(b, a % b); } ll lcm(ll a, ll b) { ll k; k = a * b / (gcd(a, b)); return k; } ll n, m; typedef struct { int to; int w; int next; } z; z edge[400010]; int head[100010]; int u, v, w; int cnt = 0; int a[100010][35]; queue<int> q; void add(int x, int y, int z) { edge[++cnt].to = y; edge[cnt].w = z; edge[cnt].next = head[x]; head[x] = cnt; } int flag = 0, vis[100010], h = 0, k[35]; void bfs() { while (!q.empty()) { int s = q.front(); q.pop(); h++; for (int i = head[s]; i != -1; i = edge[i].next) { int to = edge[i].to; int w = edge[i].w; if (!vis[to]) { vis[to] = 1; q.push(to); for (int j = 30; j >= 0; j--) { if (w >= qpow(2, j)) { w -= qpow(2, j); a[to][j] = 1 - a[s][j]; k[j] += a[to][j]; } else { a[to][j] = a[s][j]; k[j] += a[to][j]; } } } else { for (int j = 30; j >= 0; j--) { if (w >= qpow(2, j)) { w -= qpow(2, j); if (a[to][j] != 1 - a[s][j]) flag = 1; } else { if (a[to][j] != a[s][j]) flag = 1; } } } } } } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n >> m; memset(head, -1, sizeof head); for (int i = 1; i <= m; i++) { cin >> u >> v >> w; add(u, v, w); add(v, u, w); } ll sum = 0; for (int i = 1; i <= n; i++) { // cout<<i<<endl; if (!vis[i]) { h = 0;//这一次遍历过几个数 for (int j = 0; j <= 30; j++) k[j] = 0; vis[i] = 1; q.push(i); bfs(); for (int j = 0; j <= 30; j++) { // cout<<j<<" "<<k[j]<<endl; sum += min(k[j], h - k[j]) * qpow(2, j); } } } if (flag) cout << -1 << endl; else cout << sum << endl; }
J题:
题意:t次询问,每次询问包含两个数,由第一个数最少进行几个操作可以得到第二个数。每次的操作为可以将连续的相邻位+1或-1;
做法:bfs枚举所有情况,跑一个最短路,预处理;
代码:
#include<bits/stdc++.h> #include<algorithm> #include<set> #include<queue> using namespace std; #define ll long long const int mod = 998244353; ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) { ans = ans * a % mod; } a = a * a % mod; b >>= 1; } return ans; } ll gcd(ll a, ll b) // 求最大公因数 { return b == 0 ? a : gcd(b, a % b); } ll lcm(ll a, ll b) { ll k; k = a * b / (gcd(a, b)); return k; } int d[10][4] = { {0,0,0,1}, {0,0,1,0}, {0,1,0,0}, {1,0,0,0}, {0,0,1,1}, {0,1,1,0}, {1,1,0,0}, {0,1,1,1}, {1,1,1,0}, {1,1,1,1} }; ll h[100008]; ll f[2] = { 1,-1 }; queue<ll>q; int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); ll t; cin >> t; memset(h, 0x3f3f3f3f, sizeof(h)); h[0] = 0; q.push(0); while (!q.empty()) { ll now = q.front(); ll tmp = now; q.pop(); int num[4]; for (int i = 0; i < 4; ++i) { num[i] = tmp % 10; tmp /= 10; } ll num1[4]; for (int w = 0; w < 2; w++) { for (int i = 0; i < 10; i++) { ll s1 = 0; ll s2 = 1; for (int j = 0; j < 4; j++) { num1[j] = num[j] + f[w] * d[i][j] + 10; num1[j] %= 10; s1 += s2 * num1[j]; s2 *= 10; }if (h[s1] > h[now] + 1) { h[s1] = h[now] + 1; q.push(s1); } } } } while (t--) { ll a, b; cin >> a >> b; ll s = 0; for (int i = 0; i < 4; i++) { s *= 10; s += (b % 10 - a % 10 + 10) % 10; a /= 10; b /= 10; } cout << h[s] << "\n"; } }