大二第一次东北团队训练赛
这次A的题全是亮哥敲的,丧失也出了不少思路,基本就我在躺,得让自己的思路和代码能力迅速提高起来,尽自己最大的力量吧。
比赛后又敲了一遍。
A.给前三个数求第k项,需判断是等差还是等比数列。
#include<iostream> #include<stdio.h> using namespace std; const long long mod = 200907; long long a[4]; long long sort_pow(long long k, long long m){ if(k == 0) return 1; if(k % 2){ long long uu = sort_pow(k/2, m); return (uu*uu*m) % mod; }else{ long long uu = sort_pow(k/2, m); return (uu*uu) % mod; } } int main(){ long long t; scanf("%I64d", &t); while(t--){ for(long long i = 0; i < 3; i++){ scanf("%I64d", &a[i]); } long long k; scanf("%I64d", &k); if(a[2] - a[1] == a[1] - a[0]){ printf("%I64d\n", ((a[2] -a[1]) % mod *(k-1)+a[0]) %mod); }else{ printf("%I64d\n", (a[0] * sort_pow(k-1,a[1]/a[0]))% mod); } } }
B.两种操作
M a b。把a所在的堆放到b所在的堆上面。
C a:问a下面有多少箱子
就是带权并查集,不过好久没敲代码了,敲得又慢bug又多,最后还是星星重构了一遍过了
#include<iostream> #include<string.h> #include<stdio.h> using namespace std; const int maxa = 30005; int fa[maxa]; int val[maxa]; int up_box[maxa]; int find(int i){ if(i == fa[i]){ return i; } find(fa[i]); val[i] += val[fa[i]]; return fa[i] = fa[fa[i]]; } void add(int x, int y){ int fx = find(x); int fy = find(y); int upx = up_box[fx]; int upy = up_box[fy]; if(fx != fy){//printf("*"); fa[fx] = upy; val[fx] = 1; up_box[fy] = upx; } } int main(){ int n; while(scanf("%d", &n)!=EOF){ for(int i = 1; i < maxa; i++){ fa[i] = i; val[i] = 0; up_box[i] = i; } while(n--){ char c; scanf("\n%c", &c); if(c == 'M'){ int a, b; scanf("%d%d", &a, &b); add(a, b); }else{ int a; scanf("%d", &a); find(a); printf("%d\n", val[a]); } } /*for(int i = 1; i <= 6; i++){ find(i); printf("%d ", val[i]); }*/ } }
C.每次能把两行或者两列互换,只换列就可以,如果某一列第x个位置是1,那么他就可以和x建立一个联系,如果只换列不可以的话换行也是不行的,将列想成是男人,行想成是女人,如果换行的话说明两个女人调换了,那么对能否能够全部匹配上并没有影响,并查集模板。
#include<iostream> #include<string.h> #include<stdio.h> #include<vector> using namespace std; const int maxa = 104; int mp[maxa][maxa]; vector<int>g[maxa]; int from[maxa], tot; bool use[maxa]; int n; bool match(int x){ for(int i = 0;i < g[x].size(); i++){ if(!use[g[x][i]]){ use[g[x][i]] = true; if(from[g[x][i]] == -1 || match(from[g[x][i]])){ from[g[x][i]] = x; return true; } } } return false; } int hunger(){ tot = 0; memset(from, 255, sizeof(from)); for(int i = 1; i <= n; i++){ memset(use, 0, sizeof(use)); if(match(i)) ++tot; } return tot; } int main(){ while(scanf("%d", &n)!=EOF){ for(int i = 1; i <= n; i++) g[i].clear(); for(int i = 0; i < n; i++){ for(int k = 0;k < n; k++){ scanf("%d", &mp[i][k]); } } for(int i = 0; i < n; i++){ for(int k = 0; k <n ; k++){ if(mp[k][i]){ g[k+1].push_back(i+1); } } } if(hunger() == n){ int sum = 0; int ans[maxa][2]; int m = n; while(m--) for(int i = 1; i <= n; i++){ if(from[i] != i){ int a = ans[sum][0] = i; int b = ans[sum++][1] = from[i]; swap(from[a], from[b]); } } printf("%d\n", sum); for(int i =0 ;i < sum; i++){ printf("C %d %d\n", ans[i][0], ans[i][1]); } }else printf("-1\n"); } }
D.给出n个数,形成队列必须两两之差不大于k,问有多少种情况。
亮哥思路每次从1到n依次往里面插,插m的时候找出m-1时的所有种情况,比m-k小的全用"_" 表示,每次状态都会减一,思路吊的不行。
#include<iostream> #include<string.h> #include<stdio.h> #include<map> #include<vector> using namespace std; const int maxa = 55; #define LL long long vector<LL> v[maxa]; map<LL, LL> mp[maxa]; const int mod = 1000000007; LL pow[20]; int make_numb(LL x, LL num[], LL cut[]){ int o =0; LL xx = x; LL uu = 0; while(xx){ num[o] = xx%10; xx /= 10; uu+=pow[o]*num[o]; cut[o] = uu; o++; } return o; } LL comp(LL num[], int o, int i, int m){ /* printf("%d\n", i); cout<<"===="<<endl; for(int i = o -1; i >= 0; i--){ cout<<num[i]; }puts("");*/ LL u = 0; if(i<= m+1){ for(int i = o-1; i >= 0; i--){ u = u*10+num[i]; } return u; }//printf("******"); for( int i = 0;i < o; i++){ if(num[i] != 1) num[i] --; } /* cout<<"===="<<endl; for(int i = o -1; i >= 0; i--){ cout<<num[i]; }puts("");*/ LL uu = num[o-1]; for(int i = o-2; i >= 0; i--){ if(num[i] == num[i+1] && num[i] == 1){ continue; } uu = uu * 10 + num[i]; } //cout<<uu<<endl; return uu; } int main(){ int n, m; pow[0] = 1; for(int i = 1; i< 20; i++){ pow[i] = pow[i-1]*10; } LL num1[20], cut1[20]; LL num[20], cut[20]; while(scanf("%d%d", &n, &m)!=EOF){ for(int i = 0; i <= n+2; i++){ v[i].clear(); mp[i].clear(); } if(m == 0){ v[2].push_back(1); mp[2][1] = 1; } else{ v[2].push_back(2); mp[2][2] = 1; } for(int i = 3; i <= n+1; i++){ //cout<<"i=="<<i<<endl; for(int j = 0; j < v[i-1].size(); j ++){ int o = make_numb(v[i-1][j], num, cut); int ii = min(i, m+2); for(int k = 0; k <= o; k++){ //cout<<"**"<<v[i-1][j]<<endl; LL u = -1; if(k == 0 ){ if(num[k] != 1) u = ii + v[i-1][j]*10; //cout<<"qian"<<u<<endl; }else if(k == o){ if(num[k-1] != 1) u = v[i-1][j] + ii*pow[o]; //cout<<"hou"<<u<<endl; }else{ if(num[k]!= 1 &&num[k-1] != 1){ u = cut[k-1] +10*(v[i-1][j] -cut[k-1])+ pow[k]*ii; } //cout<<"zhong"<<u<<" "<<cut[k-1]<<" "<<v[i-1][j] -cut[k-1]<<endl; } if(u != -1){ int oo = make_numb(u, num1, cut1); /*for(int j = 0; j < oo; j++){ cout<<num1[j]; }printf("\n");*/ u = comp(num1, oo, i, m); //cout<<"u == "<<u<<endl; if(!mp[i][u]){ v[i].push_back(u); } mp[i][u] += mp[i-1][v[i-1][j]]; mp[i][u] %= mod; } } }//cout<<"<<"<<endl;3 /*for(int k = 0; k < v[i].size(); k++){ cout<<v[i][k]<<" " <<mp[i][v[i][k]]<<endl; }*/ } //cout<<endl; LL ans = 0; for(int i = 0; i < v[n+1].size(); i++){ //cout<<v[n+1][i]<<" "<<mp[n+1][v[n+1][i]]<<endl;; ans += mp[n+1][v[n+1][i]]; ans %= mod; } cout<<ans<<endl; } }
E。所有人都没敢做,结果就是个暴力深搜,优化都不用
#include<iostream> #include<string.h> #include<stdio.h> using namespace std; const int maxa = 30; char str[maxa][maxa]; int mp[maxa][maxa]; int ans[maxa*maxa]; int Move[4][2] = {1, 0, -1, 0, 0, 1, 0, -1}; int o, n, m; int anser[4] = {'D','U', 'R', 'L'}; int judge(int x, int y){ if(0 <= x && x < n && 0 <= y && y < m){ return 1; }return 0; } int dfs(int ax, int ay, int x, int y, int sum){ if(sum == 0){ printf("%d\n%d\n", ax, ay); for(int i = 0;i < o; i++){ printf("%c", anser[ans[i]]); }puts(""); return 1; } for(int i = 0; i < 4; i++){ int vx = Move[i][0]; int vy = Move[i][1]; int xx = x + vx; int yy = y + vy; if(judge(xx, yy) && mp[xx][yy]==0){ while(1){ xx += vx; yy += vy; if(judge(xx, yy)){ if(mp[xx][yy]){ int s = sum; int v = mp[xx][yy]; int vv = mp[xx+vx][yy+vy]; mp[xx][yy] = 0; mp[xx+vx][yy+vy] += v-1; if(judge(xx + vx, yy+ vy)){ sum --; }else{ sum -= v; } ans[o++] = i; if(dfs(ax, ay, xx, yy, sum)){ return 1; } o--;; mp[xx][yy] = v; mp[xx+vx][yy+vy] = vv; sum = s; break; } }else break; } } } return 0; } int main(){ while(scanf("%d%d", &m, &n)!=EOF){ for(int i = 0; i < n; i++){ scanf("%s", str[i]); } int sum = 0; for(int i = 0;i < n; i++){ for(int k = 0; k < m ; k++){ if(str[i][k] =='.'){ mp[i][k] = 0; }else{ mp[i][k] = str[i][k] - 'a' +1; } sum += mp[i][k]; } } int ok = 0; o = 0; for(int i = 0; i < n; i++){ for(int k = 0; k < m; k++){ if(mp[i][k] == 0){ if(dfs(i, k, i, k, sum)){ ok = 1; break; } } } if(ok) break; } } } /* 25 25 aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa ......................... ......................... aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaa */
H.赤裸裸欧拉函数模板
#include<iostream> #include<string.h> #include<stdio.h> using namespace std; const int maxa = 3000005; int minDiv[maxa], phi[maxa];//, sum[maxa]; void genphi(){ for(int i = 1; i < maxa; i++){ minDiv[i] = i; } for(int i = 2; i * i < maxa; i++){ if(minDiv[i] ==i){ for(int j = i*i; j < maxa; j += i){ minDiv[j] = i; } } } phi[1] = 1; for(int i = 2; i < maxa; i++){ phi[i] = phi[i/minDiv[i]]; if((i/minDiv[i]) % minDiv[i] == 0){ phi[i] *= minDiv[i]; }else{ phi[i] *= minDiv[i] - 1; } } } int main(){ int a, b; genphi(); while(scanf("%d%d", &a, &b)!=EOF){ long long anser = 0; for(int i = a; i <= b; i++){ anser+= phi[i]; } cout<<anser<<endl; } }
G.给出m个单词,求长度为n的字符串里包含k个单词的字符串有多少种情况,ac自动机加状压dp
dp[i][j][k]表示长度为i再自动机中的节点为j时包含k种字符有多少情况
#include<iostream> #include<string.h> #include<stdio.h> #include<algorithm> #include<queue> using namespace std; const int MOD = 20090717; int n, m, k; int dp[30][110][1<<10]; int num[5000]; struct Tire{ int next[110][26], fail[110], end[110]; int root, L; int newnode(){ for(int i = 0; i < 26; i++){ next[L][i] = -1; } end[L++] = 0; return L-1; } void init(){ L = 0; root = newnode(); } void insert(char buf[], int id){ int len = strlen(buf); int now = root; for(int i = 0; i < len; i++){ if(next[now][buf[i] - 'a'] == -1) next[now][buf[i]-'a'] = newnode(); now = next[now][buf[i]-'a']; } end[now] |= (1<<id); } void build(){ queue<int>Q; fail[root] = root; for(int i = 0; i < 26; i++){ if(next[root][i] == -1) next[root][i] = root; else{ fail[next[root][i]] = root; Q.push(next[root][i]); } } while(!Q.empty()){ int now = Q.front(); Q.pop(); end[now] |= end[fail[now]]; for(int i = 0; i < 26; i++){ if(next[now][i] == -1) next[now][i] = next[fail[now]][i]; else{ fail[next[now][i]] = next[fail[now]][i]; Q.push(next[now][i]); } } } } int solve(){ for(int i = 0; i <= n; i++){ for(int j = 0; j < L; j ++){ for(int p = 0; p < (1<<m); p++){ dp[i][j][p] = 0; } } } dp[0][0][0] = 1;//printf("*"); for(int i = 0; i < n; i++) for(int j = 0; j < L; j++) for(int p = 0; p < (1<<m); p++) if(dp[i][j][p] > 0){ for(int x = 0; x < 26; x++){ int newi = i+1; int newj = next[j][x]; int newp = (p|end[newj]); //printf("%d %d %d %d\n",n, i, j, p); dp[newi][newj][newp] += dp[i][j][p]; dp[newi][newj][newp] %= MOD; } } int ans = 0; for(int p = 0; p < (1<<m); p ++){ if(num[p] < k) continue; for(int i = 0; i < L; i++){ ans = (ans + dp[n][i][p])%MOD; } } return ans; } }; char buf[20]; Tire ac; int main(){ for(int i = 0; i < (1<<10); i++){ num[i] = 0; for(int j = 0; j < 10; j++) if(i & (1<<j)) num[i]++; } while(scanf("%d%d%d", &n, &m, &k)!=EOF){ if(n==0 && m==0 && k == 0) return 0; ac.init(); for(int i = 0;i < m; i++){ scanf("%s", buf); ac.insert(buf, i); } ac.build(); printf("%d\n", ac.solve()); } }
F。广搜
#include<iostream> #include<string.h> #include<stdio.h> #include<queue> using namespace std; const int maxa = 1105; char str[maxa][maxa]; int vis[maxa][maxa]; int n, m; int str_x, str_y, end_x, end_y; struct point{ int x, y, vis; bool operator < (const point& a) const { return a.vis < vis; } }; int Move[4][2] = {1, 0, -1, 0, 0, 1, 0, -1}; int judge(int x, int y){ if(0 <= x && x < n && 0 <= y && y < m && vis[x][y] == -1){ return 1; }return 0; } priority_queue<point>q; int ok;/* int dfs(int x, int y, int u){ if(ok)return 1; if(judge(x,y) && str[x][y] == 'X'){ vis[x][y] = u; q.push(point{x,y, u}); for(int i = 0; i < 4; i++){ dfs(x+Move[i][0], y+Move[i][1], u); } } if(x == end_x && y == end_y) ok = 1; }*/ int bfs(){ ok = 0; while(!q.empty())q.pop(); memset(vis, -1, sizeof(vis)); vis[str_x][str_y] = 0; q.push(point{str_x, str_y, 0}); while(!q.empty()){ point New = q.top(); q.pop(); if(ok == 1) break; // printf("%d %d\n",New.x, New.y); for(int i = 0; i < 4; i++){ int xx = New.x+Move[i][0]; int yy = New.y + Move[i][1]; if(!judge(xx, yy))continue; if(str[xx][yy] == '.'){ vis[xx][yy] = vis[New.x][New.y]+1; q.push(point{xx, yy,vis[xx][yy]}); }else{ vis[xx][yy] = vis[New.x][New.y]; q.push(point{xx,yy,vis[xx][yy]}); } } } } int main(){ //freopen("in.cpp", "r", stdin); while(scanf("%d%d", &n, &m)!=EOF){ if(n== 0 && m == 0)break; for(int i = 0;i < n; i++){ scanf("%s", &str[i]); } scanf("%d%d%d%d", &str_x, &str_y, &end_x, &end_y); str_x--,str_y--,end_x--,end_y--; bfs(); printf("%d\n", vis[end_x][end_y]); }return 0; }