三道题全是搜索,前两道傻逼题,T3码量巨长node
指望 \(AK\) ,实际得分 \(60 + 100 + 65 = 225pts\)ios
读错题的都是士兵git
数据都很小,暴力搜索便可数组
注意枚举第一个数可取的范围,注意全部数都必须是正整数spa
/* Work by: Suzt_ilymics Knowledge: ?? Time: O(??) 评测机别偷懒,赛后给您加鸡腿 */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define LL long long #define orz cout<<"lkp AK IOI!"<<endl using namespace std; const int MAXN = 1; const int INF = 1; const int mod = 1; int n, S, p; int cnt = 0; int read(){ int s = 0, f = 0; char ch = getchar(); while(!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return f ? -s : s; } void dfs(int pos, int val, int pre){ // printf("%d\n", val); if(pos == n + 1) { if(val == S) cnt++; return ; } int cnt = n - pos + 1; if(cnt * pre + (cnt + 1) * cnt / 2 * p + val < S) return ; if(cnt * pre - (cnt + 1) * cnt / 2 * p + val > S) return ; for(int i = -p; i <= p; ++i){ if(pre + i > 0) dfs(pos + 1, val + pre + i, pre + i); } } int main() { // freopen("math.in","r",stdin); // freopen("math.out","w",stdout); n = read(), S = read(), p = read(); // int Minn = (S - n * (n - 1) / 2 * p) / n; int Maxn = (S + n * (n - 1) / 2 * p) / n; for(int i = 1; i <= Maxn; ++i){ // for(int i = -29; i <= 60; ++i){ dfs(2, i, i); } printf("%d", cnt); return 0; }
Problem 2 网格(grid.cpp/c/pas)code
/* Work by: Suzt_ilymics Knowledge: ?? Time: O(??) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define LL long long #define orz cout<<"lkp AK IOI!"<<endl using namespace std; const int MAXN = 1010; const int INF = 1; const int mod = 1; int dx[4] = {0, 0, 1, -1}; int dy[4] = {1, -1, 0, 0}; struct node{ int x, y, val; }; int n, sx, sy, ex, ey; int a[MAXN][MAXN], ans[MAXN][MAXN]; bool vis[MAXN][MAXN]; queue<node> q; int read(){ int s = 0, f = 0; char ch = getchar(); while(!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return f ? -s : s; } bool ligit(int x, int y){ return (x > 0 && y > 0 && x <= n && y <= n); } void bfs(){ q.push((node){sx, sy, 0}); while(!q.empty()){ node t = q.front(); q.pop(); ans[t.x][t.y] = t.val; if(t.x == ex && t.y == ey) return ; for(int i = 0; i < 4; ++i){ node v; v.x = t.x + dx[i], v.y = t.y + dy[i], v.val = t.val + 1; if(!vis[v.x][v.y] && ligit(v.x, v.y) && (a[v.x][v.y] == 0)){ q.push(v); vis[v.x][v.y] = 1; } } } } int main() { // freopen("grid.in","r",stdin); // freopen("grid.out","w",stdout); memset(ans, -1, sizeof(ans)); n = read(); for(int i = 1; i <= n; ++i){ for(int j = 1; j <= n; ++j){ a[i][j] = read(); } } sx = read(), sy = read(), ex = read(), ey = read(); bfs(); printf("%d", ans[ex][ey]); return 0; }
每一个格子只有两种填法且 \(n \le 7\),暴力搜索两种填法,开 \(cnt\) 数组统计链接个数。get
填一个格子,若是是 "\",格子左上角和右下角的 \(cnt++\),若是是 "/",格子左下角和右上角的 \(cnt++\) 。只有更改后的 \(cnt\) 小于等于目标 \(cnt\) 才继续向下搜,不然回溯数学
发现每填一个格子,链接格子左上角的格点的个数就能够被肯定,那么只有左上角的格点个数等于目标格点个数或没有要求才继续搜索,不然回溯
若是搜索到第 \(n + 1\) 列时,要额外判断边界第 \(n + 1\) 列的 \(cnt\) 是否知足对应的个数
若是搜索到第 \(n\) 行时,要额外判断边界第 \(n + 1\) 行的 \(cnt\) 是否知足对应个数
如何保证无环?
不难想到,只有在填 "/" 时才有可能出现环,那么在填 "/" 以前,先判断是否有环
如何处理点的坐标?把行看作十位,把列看作个位就好啦
算法一:考虑可撤销并查集,然而我不会
算法二:发现n很小,没次判断时 \(n^2\) 扫一遍建图,在 \(dfs\)看看可否从左下角跑到右上角
算法三:很显然算法二很傻逼,直接用并查集维护就好,加完边后判断左下角和右上角是否在同一并查集里,省去 \(dfs\)的时间
最后输出方案就好啦
/* Work by: Suzt_ilymics Knowledge: ?? Time: O(??) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define LL long long #define orz cout<<"lkp AK IOI!"<<endl using namespace std; const int MAXN = 10; const int INF = 1; const int mod = 1; struct edge{ int from, to, nxt; }e[10100 << 1]; int head[MAXN * MAXN], num_edge = 0; int n; int go[MAXN][MAXN]; int cnt[MAXN][MAXN], now[MAXN][MAXN]; bool flag = false, Flag = false; int read(){ int s = 0, f = 0; char ch = getchar(); while(!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return f ? -s : s; } void add_edge(int from, int to){ e[++num_edge] = (edge){from, to, head[from]}, head[from] = num_edge; } bool bl(int u, int fa, int end){ for(int i = head[u]; i != -1; i = e[i].nxt){ int v = e[i].to; if(v == fa) continue; if(v == end) { Flag = 1; return true; } bl(v, u, end); if(Flag) { return true; } } return false; } bool pd(int sx, int sy, int ex, int ey){ memset(head, -1, sizeof(head)); num_edge = 0; Flag = false; for(int i = 1; i <= n; ++i){ for(int j = 1; j <= n; ++j){ if(now[i][j] == 0){ add_edge(i * 10 + j, (i + 1) * 10 + j + 1); add_edge((i + 1) * 10 + j + 1, i * 10 + j); } if(now[i][j] == 1){ add_edge((i + 1) * 10 + j, i * 10 + j + 1); add_edge(i * 10 + j + 1, (i + 1) * 10 + j); } } } if(bl(sx * 10 + sy, 0, ex * 10 + ey)) return 1; else return 0; } void dfs(int posx, int posy){ // cout<<posx<<" "<<posy; // orz; if(posx == n && posy == n + 1) { if( ((cnt[posx + 1][posy] == go[posx + 1][posy]) || (go[posx + 1][posy] == 9)) && ((cnt[posx][posy] == go[posx][posy]) || (go[posx][posy] == 9)) ) flag = 1; return ; }// 若是搜到最后一个点,说明已经找到答案。退出 if(posy == n + 1){ //若是这一行搜完了 if((cnt[posx][posy] == go[posx][posy]) || (go[posx][posy] == 9) ) posx++, posy = 1;//换行 else return ;// 若是已经肯定的那个数并无达到目标,返回 }// now[posx][posy] = 0;// 填 "\" cnt[posx][posy]++, cnt[posx + 1][posy + 1]++;// 对应位置加1 if(cnt[posx][posy] <= go[posx][posy] && cnt[posx + 1][posy + 1] <= go[posx + 1][posy + 1]) {//若是两个对应位置大于目标位置就不向下搜索 if((go[posx][posy] != 9 && go[posx][posy] == cnt[posx][posy]) || (go[posx][posy] == 9)) {//若是已经肯定的那个数没有达到目标,中止向下搜索 if((posx != n) || (posx == n && ( (go[posx + 1][posy] != 9 && go[posx + 1][posy] == cnt[posx + 1][posy]) || (go[posx + 1][posy] == 9) ) )){ dfs(posx, posy + 1);// } } }// if(flag) return ;// 若是找到答案就返回 cnt[posx][posy]--, cnt[posx + 1][posy + 1]--;//回溯 if(pd(posx + 1, posy, posx, posy + 1)){ return ;} now[posx][posy] = 1;// 填 "/" cnt[posx + 1][posy]++, cnt[posx][posy + 1]++;// 对应位置加1 if(cnt[posx + 1][posy] <= go[posx + 1][posy] && cnt[posx][posy + 1] <= go[posx][posy + 1]) {//若是两个对应位置大于目标位置就不向下搜索 if((go[posx][posy] != 9 && go[posx][posy] == cnt[posx][posy]) || (go[posx][posy] == 9)) {//若是已经肯定的那个数没有达到目标,中止向下搜索 if((posx != n) || (posx == n && ( (go[posx + 1][posy] != 9 && go[posx + 1][posy] == cnt[posx + 1][posy]) || (go[posx + 1][posy] == 9) ) )){ dfs(posx, posy + 1);// } } } if(flag) return ;// 若是找到答案就返回 now[posx][posy] = -1;//回溯 cnt[posx + 1][posy]--, cnt[posx][posy + 1]--;// 回溯 } int main() { // freopen("gokigen.in","r",stdin); // freopen("gokigen.out","w",stdout); int T; T = read(); while(T--){ n = read(); memset(now, -1, sizeof(now)); memset(cnt, 0, sizeof(cnt)); memset(go, 0, sizeof(go)); flag = 0; char ch[10]; for(int i = 1; i <= n + 1; ++i){ cin>>(ch + 1); for(int j = 1; j <= n + 1; ++j){ if(isdigit(ch[j])) go[i][j] = ch[j] - '0'; else go[i][j] = 9; } } dfs(1, 1); // for(int i = 1; i <= n + 1; ++i){ // for(int j = 1; j <= n + 1; ++j){ // cout<<go[i][j]<<" "; // } // cout<<"\n"; // } // cout<<"\n"; // // for(int i = 1; i <= n + 1; ++i){ // for(int j = 1; j <= n + 1; ++j){ // cout<<cnt[i][j]<<" "; // } // cout<<"\n"; // } // cout<<"\n"; for(int i = 1; i <= n; ++i){ for(int j = 1; j <= n; ++j){ if(now[i][j] == 1) cout<<"/"; else if(now[i][j] == 0) cout<<"\\"; else cout<<"s"; } cout<<"\n"; } } return 0; }