題目描述:有一個\(n \times m\)的\(01\)矩陣,這一矩陣第一行和最後一行是相鄰的,第一列和最後一列是相鄰的,如今每次能夠交換相鄰的兩個位置的數(四相鄰),問最少多少次操做使得每一行的\(1\)的個數相同,每一列的\(1\)的個數相同,若是不行,則最少多少次操做使得每一行的\(1\)的個數相同,若是不行,則最少多少次操做使得每一列的\(1\)的個數相同,若是不行,則輸出無解。c++
solution
行和列是獨立的,所以能夠分開作,因爲矩陣第一行和最後一行是相鄰的,所以要枚舉第一行,而後按順序填補,多則出,少則進,而後取最小值便可。ide
時間複雜度:\(O(n^2+m^2)\)this
#include <bits/stdc++.h> using namespace std; typedef long long LL; const LL inf=1LL<<60; const int maxn=1010; int n, m, total; int row[maxn], col[maxn]; void read() { scanf("%d%d", &n, &m); for (int i=1; i<=n; ++i) row[i]=0; for (int i=1; i<=m; ++i) col[i]=0; for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) { int x; scanf("%1d", &x); row[i]+=x; col[j]+=x; } } LL work(int n, int *a) { LL ans=inf; int each=total/n; for (int i=1; i<=n; ++i) { int rest=0; LL s=0; int cur=i; for (int j=1; j<=n; ++j, cur=(cur==n? 1:cur+1)) { if (a[cur]>each) { if (rest<0) { int used=min(-rest, a[cur]-each); s+=used*j; rest+=a[cur]-each; s-=(a[cur]-each-used)*j; } else { s-=(a[cur]-each)*j; rest+=a[cur]-each; } } else { if (rest>0) { int used=min(rest, each-a[cur]); s+=used*j; rest-=each-a[cur]; s-=(each-a[cur]-used)*j; } else { s-=(each-a[cur])*j; rest-=each-a[cur]; } } } ans=min(ans, s); } return ans; } void solve() { total=0; for (int i=1; i<=n; ++i) total+=row[i]; if (total%n==0 && total%m==0) printf("both "); else if (total%n==0) printf("row "); else if (total%m==0) printf("column "); else { puts("impossible"); return; } LL ans=0; if (total%n==0) ans+=work(n, row); if (total%m==0) ans+=work(m, col); printf("%lld\n", ans); } int main() { int casesum; scanf("%d", &casesum); for (int i=1; i<=casesum; ++i) { printf("Case %d: ", i); read(); solve(); } return 0; }
solutionspa
#include <bits/stdc++.h> using namespace std; typedef long long LL; int n; int a[20], idx[1<<10]; bool flag[1<<10][210]; LL num[1<<10]; bool cmp(int b, int c) { return num[b]<num[c]; } void init() { for (int sett=0; sett<1<<10; ++sett) { int cnt=0; for (int i=0; i<10; ++i) if (sett>>i & 1) a[++cnt]=i; num[sett]=0; for (int i=cnt; i; --i) num[sett]=num[sett]*10+a[i]; for (int i=1; i<=cnt; ++i) { flag[sett][a[i]]=true; for (int j=1; j<=cnt; ++j) if (i!=j) { flag[sett][a[i]*10+a[j]]=true; flag[sett][a[i]+a[j]]=true; for (int k=1; k<=cnt; ++k) if (i!=k && j!=k) { flag[sett][a[i]*10+a[j]+a[k]]=true; for (int p=1; p<=cnt; ++p) if (i!=p && j!=p && k!=p) flag[sett][a[i]*10+a[j]+a[k]*10+a[p]]=true; } } } } for (int i=0; i<1<<10; ++i) idx[i]=i; sort(idx, idx+(1<<10), cmp); } bool read() { scanf("%d", &n); for (int i=1; i<=n; ++i) scanf("%d", &a[i]); return n; } void solve() { for (int i=0; i<1<<10; ++i) { bool can=true; for (int j=1; j<=n && can; ++j) can&=flag[idx[i]][a[j]]; if (can) { printf("%lld\n", num[idx[i]]); return; } } } int main() { init(); int casesum=0; while (read()) { printf("Case %d: ", ++casesum); solve(); } return 0; }
題目描述:一副\(54\)張的撲克牌,隨機排序,按順序抽取,抽到大小王可讓他們變成任意一種花色(要當場決定),問指望抽多少張牌使得每種花色至少有\(A, B, C, D\)張。rest
solution
機率\(dp\),思路挺好想的,就記住每種花色剩下多少張,以及每一個王變成了什麼花色(或者還沒抽到)code
時間複雜度:\(O(13^4*5^2*4)\)(每次詢問)排序
題目描述:給定一個\(n \times m\)的網格圖,在圖中畫兩個圓,要求者兩個圓的圓心要在格點上,半徑要是整數(兩個圓的半徑不必定相等),整個圓要在網格圖內,兩個圓要相切,問方案數。ci
solution
先預處理出兩個圓所造成的矩形的狀況,以及每種狀況對應的方案數,而後問題就變成了給定的網格圖每種矩形有多少個。
預處理這部分能夠枚舉兩個圓心橫座標的差以及縱座標的差,判斷是否能相切(其實就是判勾股數),而後再枚舉其中一個圓的半徑,就能夠算出兩個圓所對應的矩形,而後統計結果。it
時間複雜度:\(O(能過)\)(由於勾股數很少)io
題目描述:在二維平面上,給出一個矩形的頂點座標,在給定在矩形內的四個點,問這四個點要如何移動,使得移動後四個點的重心與矩形重心重合,而且移動的距離總和最小,求移動後的座標。
solution
能夠先把矩形的重心移到原點,而後算出四個點的重心,重心指向原點的向量就是四個點的移動的向量的總和,由於要移動的距離總和最小,所以全部點的移動的向量應與重心指向原點的向量平行,而後逐個移動便可。
時間複雜度:\(O(1)\)
#include <bits/stdc++.h> using namespace std; #define x first #define y second typedef long double LD; const LD eps=1e-15; const LD inf=1e18; struct Point:public pair<LD, LD> { Point(LD _x=0, LD _y=0):pair(_x, _y){} Point& operator += (Point c) { x+=c.x; y+=c.y; return *this; } Point& operator /= (LD c) { x/=c; y/=c; return *this; } Point& operator -= (Point c) { x-=c.x; y-=c.y; return *this; } Point operator + (Point c) { return Point(x+c.x, y+c.y); } Point operator - (Point c) { return Point(x-c.x, y-c.y); } Point operator * (LD c) { return Point(x*c, y*c); } Point operator / (LD c) { return Point(x/c, y/c); } bool zero() { return (fabs(x)<eps && fabs(x)<eps); } void rotate(LD angle) { LD tmp=x; x=-sin(angle)*y+cos(angle)*tmp; y=sin(angle)*tmp+cos(angle)*y; } }; Point origin; LD angle; Point pos[10], rec[10], ans[10]; inline LD sqr(LD x) { return x*x; } LD dis(Point b, Point c) { return sqrt(sqr(b.x-c.x)+sqr(b.y-c.y)); } bool read() { for (int i=1; i<=4; ++i) scanf("%Lf%Lf", &pos[i].x, &pos[i].y); for (int i=1; i<=4; ++i) scanf("%Lf%Lf", &rec[i].x, &rec[i].y); for (int i=1; i<=4; ++i) if (fabs(pos[i].x)>eps || fabs(pos[i].y)>eps) return true; for (int i=1; i<=4; ++i) if (fabs(rec[i].x)>eps || fabs(rec[i].y)>eps) return true; return false; } void rotate() { origin=Point(0, 0); for (int i=1; i<=4; ++i) origin+=rec[i]; origin/=4; for (int i=1; i<=4; ++i) { rec[i]-=origin; pos[i]-=origin; } Point arrow=rec[2]-rec[1]; angle=atan2(arrow.y, arrow.x); for (int i=1; i<=4; ++i) { rec[i].rotate(-angle); pos[i].rotate(-angle); } } void solve() { rotate(); Point total=Point(0, 0); Point boundx=Point(inf, -inf), boundy=Point(inf, -inf); for (int i=1; i<=4; ++i) total-=pos[i]; for (int i=1; i<=4; ++i) { boundx.x=min(rec[i].x, boundx.x); boundx.y=max(rec[i].x, boundx.y); boundy.x=min(rec[i].y, boundy.x); boundy.y=max(rec[i].y, boundy.y); } LD answer=0; for (int i=1; i<=4; ++i) { Point bound=Point((total.x<0? boundx.x:boundx.y), (total.y<0? boundy.x:boundy.y)); Point tmp=bound-pos[i]; LD rate=min(LD(1.0), min(tmp.x/total.x, tmp.y/total.y)); tmp=pos[i]+total*rate; total-=tmp-pos[i]; answer+=dis(pos[i], tmp); pos[i]=tmp; } for (int i=1; i<=4; ++i) { pos[i].rotate(angle); pos[i]+=origin; } for (int i=1; i<=4; ++i) printf("%.12Lf %.12Lf\n", pos[i].x, pos[i].y); puts(""); } void readans() { for (int i=1; i<=4; ++i) scanf("%Lf%Lf", &ans[i].x, &ans[i].y); LD answer=0; for (int i=1; i<=4; ++i) answer+=dis(ans[i], pos[i]); printf("%.12Lf\n", answer); } int main() { while (read()) solve(); return 0; }
題目描述:有兩種\(2 \times 2\)的地磚,如圖,如今有\(n \times m\)塊地磚拼在一塊兒,以圓弧連成的線做爲分界進行塗色,給出一些詢問,每次給定一個座標,問該座標所在的區域的面積。
solution
將一塊地磚分紅三個區域,而後題目的意思作並查集,再處理出每一個座標所在的並查集。
時間複雜度:\(O(nm)\)
#include <bits/stdc++.h> using namespace std; const double PI=acos(-1); const int maxn=110; int n, m; int dsu[maxn*maxn*4]; double area[maxn*maxn*4]; bool Map[maxn][maxn]; int pos[maxn*2][maxn*2]; void read() { scanf("%d%d", &n, &m); for (int i=1; i<=n*m*3; i+=3) { dsu[i]=dsu[i+1]=dsu[i+2]=-1; area[i]=area[i+2]=PI/4; area[i+1]=2*2-PI/2; } for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) scanf("%1d", &Map[i][j]); } int dsu_find(int cur) { return (dsu[cur]<0? cur:(dsu[cur]=dsu_find(dsu[cur]))); } void merge(int u, int v) { u=dsu_find(u); v=dsu_find(v); if (u==v) return; if (dsu[u]>dsu[v]) swap(u, v); dsu[u]+=dsu[v]; dsu[v]=u; area[u]+=area[v]; } void divide() { for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) { int cur=((i-1)*m+j-1)*3; if (i!=1) { int nx=((i-2)*m+j-1)*3; if (Map[i][j]==Map[i-1][j]) { merge(nx+2, cur+1); merge(nx+3, cur+2); } else { merge(nx+3, cur+1); merge(nx+2, cur+2); } } if (j!=1) { int nx=((i-1)*m+j-2)*3; if (Map[i][j]) { if (Map[i][j-1]) { merge(nx+1, cur+2); merge(nx+2, cur+3); } else { merge(nx+2, cur+2); merge(nx+3, cur+3); } } else { if (Map[i][j-1]) { merge(nx+1, cur+1); merge(nx+2, cur+2); } else { merge(nx+2, cur+1); merge(nx+3, cur+2); } } } } } void calc_pos() { for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) { pos[(i-1)*2][j*2-1]=pos[i*2-1][(j-1)*2]=pos[i*2-1][j*2]=pos[i*2][j*2-1]=0; if (Map[i][j]) { pos[(i-1)*2][j*2]=((i-1)*m+j-1)*3+1; pos[(i-1)*2][(j-1)*2]=pos[i*2-1][j*2-1]=pos[i*2][j*2]=((i-1)*m+j-1)*3+2; pos[i*2][(j-1)*2]=((i-1)*m+j)*3; } else { pos[(i-1)*2][(j-1)*2]=((i-1)*m+j-1)*3+1; pos[(i-1)*2][j*2]=pos[i*2-1][j*2-1]=pos[i*2][(j-1)*2]=((i-1)*m+j-1)*3+2; pos[i*2][j*2]=((i-1)*m+j)*3; } } /* for (int i=0; i<=n*2; ++i, putchar('\n')) for (int j=0; j<=m*2; ++j) printf("%d ", pos[i][j]); */ } void solve() { calc_pos(); divide(); int T; scanf("%d", &T); while (T--) { int x, y; scanf("%d%d", &x, &y); if (pos[x][y]==0) printf("%.4lf\n", 0.0); else printf("%.4lf\n", area[dsu_find(pos[x][y])]); } } int main() { int casesum; scanf("%d", &casesum); for (int i=1; i<=casesum; ++i) { printf("Case %d:\n", i); read(); solve(); } return 0; }
solution
模擬。
時間複雜度:\(O(m)\)