• Dhaka2011


    Dhaka2011

    A - Binary Matrix

    题目描述:有一个(n imes m)(01)矩阵,这一矩阵第一行和最后一行是相邻的,第一列和最后一列是相邻的,现在每次可以交换相邻的两个位置的数(四相邻),问最少多少次操作使得每一行的(1)的个数相同,每一列的(1)的个数相同,如果不行,则最少多少次操作使得每一行的(1)的个数相同,如果不行,则最少多少次操作使得每一列的(1)的个数相同,如果不行,则输出无解。

    solution
    行和列是独立的,因此可以分开做,由于矩阵第一行和最后一行是相邻的,因此要枚举第一行,然后按顺序填补,多则出,少则进,然后取最小值即可。

    时间复杂度:(O(n^2+m^2))

    #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
    ", ans);
    }
    int main()
    {
    	int casesum;
    	scanf("%d", &casesum);
    	for (int i=1; i<=casesum; ++i)
    	{
    		printf("Case %d: ", i);
    		read();
    		solve();
    	}
    	return 0;
    }
    

    B - Candles

    solution

    #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
    ", num[idx[i]]);
    			return;
    		}
    	}
    }
    int main()
    {
    	init();
    	int casesum=0;
    	while (read())
    	{
    		printf("Case %d: ", ++casesum);
    		solve();
    	}
    	return 0;
    }
    

    C - Cards

    题目描述:一副(54)张的扑克牌,随机排序,按顺序抽取,抽到大小王可以让他们变成任意一种花色(要当场决定),问期望抽多少张牌使得每种花色至少有(A, B, C, D)张。

    solution
    概率(dp),思路挺好想的,就记住每种花色剩下多少张,以及每个王变成了什么花色(或者还没抽到)

    时间复杂度:(O(13^4*5^2*4))(每次询问)

    G - Pair of Touching Circles

    题目描述:给定一个(n imes m)的网格图,在图中画两个圆,要求者两个圆的圆心要在格点上,半径要是整数(两个圆的半径不一定相等),整个圆要在网格图内,两个圆要相切,问方案数。

    solution
    先预处理出两个圆所形成的矩形的情况,以及每种情况对应的方案数,然后问题就变成了给定的网格图每种矩形有多少个。
    预处理这部分可以枚举两个圆心横坐标的差以及纵坐标的差,判断是否能相切(其实就是判勾股数),然后再枚举其中一个圆的半径,就可以算出两个圆所对应的矩形,然后统计结果。

    时间复杂度:(O(能过))(因为勾股数不多)

    H - Treasure Hunt

    题目描述:在二维平面上,给出一个矩形的顶点坐标,在给定在矩形内的四个点,问这四个点要如何移动,使得移动后四个点的重心与矩形重心重合,并且移动的距离总和最小,求移动后的坐标。

    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
    ", 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
    ", answer);
    }
    int main()
    {
    	while (read()) solve();
    	return 0;
    }
    

    I - Truchet Tiling

    题目描述:有两种(2 imes 2)的地砖,如图,现在有(n imes 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('
    '))
    		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
    ", 0.0);
    		else printf("%.4lf
    ", area[dsu_find(pos[x][y])]);
    	}
    }
    int main()
    {
    	int casesum;
    	scanf("%d", &casesum);
    	for (int i=1; i<=casesum; ++i)
    	{
    		printf("Case %d:
    ", i);
    		read();
    		solve();
    	}
    	return 0;
    }
    

    J - As Long as I Learn, I Live

    solution
    模拟。

    时间复杂度:(O(m))

  • 相关阅读:
    maven中文乱码问题——打包错误
    maven中文乱码问题——编译错误
    Vue.js 十五分钟入门
    Vue+SpringBoot+Mybatis的简单员工管理项目
    vue.js+boostrap最佳实践
    Chrome教程(二)使用ChromeDevTools命令菜单运行命令
    Chrome教程(一)NetWork面板分析网络请求
    Vue.js——vue-router 60分钟快速入门
    Vue.js——60分钟组件快速入门(下篇)
    Vue.js——60分钟组件快速入门(上篇)
  • 原文地址:https://www.cnblogs.com/GerynOhenz/p/9893238.html
Copyright © 2020-2023  润新知