纪中 Day15&Day16

纪中 Day15&Day16

T1
暴力解决

T2
纯粹蒙分
跟正解有些偏差

T3
经ZZL大佬指点
快排+二分

T4
不知什么东东


T1

找路

题目
M i r k o Mirko Mirko 刚开始学车,因此他还不会在一个很狭窄的地方掉头,所以他想找一个不需要掉头的地方学车。 M i r k o Mirko Mirko马上发现他想找的地方必须没有死胡同,因为死胡同是不可能出来的,除非掉头(假设 M i r k o Mirko Mirko也不会倒车)。现在,你需要写一个程序,来分析一个地方的地图,研究是否这个地方适合 M i r k o Mirko Mirko练习开车。

这张地图是包含 R R R* C C C个单元格的,单元格中的“X”代表一个建筑物,单元格中的“.”代表路面。从一个路面单元格, M i r k o Mirko Mirko可以向旁边上下左右四个方向的单元格开去,只要开过去的地方同样也是路面。

最后,我们要得出这个地图是否包含死胡同,假如从任意一个路面单元格出发,沿着任何一个可以行驶的方向,我们可以不用掉头就能返回到出发点,那么这个地图就是没有死胡同的。

输入
第一行包括两个整数 R R R C C C(3<= R R R, C C C<=10),表示这个地图的大小。

接下来 R R R行,每行有 C C C个字符,每个字符可能是“X”和“.”。地图中至少有两个路面单元格,并且所有的路面都是相连的(相互可达的)。

输出
输出只有一行,输出0表示这个地图没有死胡同,输出1表示这个地图存在死胡同。

样例
纪中 Day15&Day16_第1张图片解题思路
暴力判断每一个路面是否有2个方向可走

代码

#include
#include
using namespace std;
int fx[5]={0,1,0,-1,0},fy[5]={0,0,1,0,-1};
int n,m,a[20][20];
char c;
int main()
{
	freopen("okret.in","r",stdin);
	freopen("okret.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
	    for (int j=1;j<=m;j++)
	    {
	    	cin>>c;
	    	if (c=='X')
	    	   a[i][j]=1;
	    	   else a[i][j]=0;
		}
	for (int i=1;i<=n;i++)
	    for (int j=1;j<=m;j++)
	    	if (a[i][j]==0)
	    	{
	    		int ans=0;
	    		for (int k=1;k<=4;k++)
	    		    if (a[i+fx[k]][j+fy[k]]==0&&i+fx[k]<=n&&i+fx[k]>0&&j+fy[k]>0&&j+fy[k]<=m)  //可走
	    		       ans++;
	    		if (ans<2)  //死胡同
	    		{
	    			cout<<1<<endl;
	    			return 0;
				}
			}
	cout<<0<<endl;
	fclose(stdin);
	fclose(stdout);
	return 0;
}

T3

家庭作业

题目
M i r k o Mirko Mirko最近收到了一个家庭作业,作业的任务是计算两个数A和B的最大公约数。由于这两个数太大了,我们给出了 N N N个数,他们的乘积是 A A A,给出 M M M个数,他们的乘积是 B B B

M i r k o Mirko Mirko想要验算自己的答案,所以他想找你写一个程序来解决这个问题。如果这个最大公约数超过了9位数,那么只需要输出最后9位就可以了。

输入
第一行包含一个正整数 N N N,范围是1到1000。第二行是 N N N个用空格隔开的正整数(小于10亿),他们的乘积是 A A A。第三行包含一个正整数 M M M,范围是1到1000。第四行是 M M M个用空格隔开的正整数(小于10亿),他们的乘积是 B B B

输出
输出有且只有一行,表示 A A A B B B的最大公约数,如果结果超过了9位数,输出最后9位数就可以了。

样例
纪中 Day15&Day16_第2张图片解题思路
先输入 N N N个数
再输入 k k k
然后跟 N N N个数找最大公约数
答案相乘
k k k和这个数都除于他们都最大公约数

代码

#include
#include
#include
using namespace std;
long long n,m,c,t,a[1200],b[10];
long long ans=1;
bool p=false;
int gy(int x,int y)
{
	int r=1;
	while (r!=0)
	{
		  r=x%y;
		  x=y;
		  y=r;
	}
	return x;
}
int main()
{
	freopen("zadaca.in","r",stdin);
	freopen("zadaca.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	    scanf("%d",&a[i]);
    scanf("%d",&m);
	for (int i=1;i<=m;i++)
	{
	    scanf("%d",&c);
	    long long x;
	    for (int j=1;j<=n;j++)
	    {
	        x=gy(c,a[j]);
	        if (ans*x>10000000000)  //相乘时超过9位,标记
	           p=true;
	        ans=ans*x%10000000000;  //相乘
	        c=c/x;
	        a[j]=a[j]/x;  //相除
	    }
	}
	while (ans>0)
	{
		  b[++t]=ans%10;
		  ans=ans/10;
	}  //倒序存储
	if (p)
	   for (int i=9;i>0;i--)  //超过9位,会有前导0的可能
	       cout<<b[i];
	   else for (int i=t;i>0;i--)  //没有超过,直接输出
	            cout<<b[i]; 
	fclose(stdin);
	fclose(stdout);
	return 0;
}

T3

算法学习

题目
自从学习了动态规划后, F a m e r Famer Famer K X P KXP KXP对动态规划的热爱便一发不可收拾,每天都想找点题做,一天,他找到了一道题,但是不会做,于是,他找到了你。题目如下:
给出 N N N个无序不重复的数,再有 M M M个询问,每次询问一个数是否在那 N N N个数中,若在,则 a n s ans ans增加2^ K K K, K K K为该数在原数列中的位置。
由于 a n s ans ans过大,所以只要求你输出 a n s ans ans m o d mod mod 10^9+7。

输入
第一行,两个数 N N N, M M M,第二行 N N N个数,第三行 M M M个数。

输出
输出最终答案。

样例
input
5 5
1 3 4 6 5
1 8 1 3 6

output
24

数据范围限制
30% 0 50% 0 100% 0 输入的数均在2^31 以内

解题思路
快排+二分

代码

#include
#include
#include
using namespace std;
const int mo=1000000007;
int n,m,x,b[100010];
long long ans;
struct hhx{
	int x,s;
}a[100010];
bool cmp(hhx t,hhx x)
{
	return (t.s<x.s);
}
void jc()
{ 
    b[1]=2;
	for (int i=2;i<=n;i++)
	    b[i]=b[i-1]*2%mo;
}
int main()
{
	freopen("sfxx.in","r",stdin);
	freopen("sfxx.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&a[i].s);
		a[i].x=i;
	}
	sort(a+1,a+n+1,cmp);  //快排
	jc();  //提前做2的n次方的积
	for (int i=1;i<=m;i++)
	{
		scanf("%d",&x);
		int l=1,r=n;
		while (l<=r)  //二分在数组里找x
		{ 
			  int mid=(l+r)/2;  
			  if (a[mid].s==x)  //找到
			  {
			  	 ans=(ans+b[a[mid].x])%mo; 
				 break;   
			  }
			  if (a[mid].s>x)  //继续找
			     r=mid-1;
			     else l=mid+1;
		}
	}
	cout<<ans<<endl;
	fclose(stdin);
	fclose(stdout);
	return 0;
}

T4

友好数对

题目:
在顺利完成家庭作业以后, M i r k o Mirko Mirko感到非常的厌倦。所以,他列出了 N N N个数,这些数中有些数对他是喜欢的,有些数对他是不喜欢的。

他喜欢的数对叫做友好数对,如果两个数至少有一个相同的数字(不要求在相同的位置),那么这两个数就是友好数对。请帮助 M i r k o Mirko Mirko在这 N N N个数找出有多少友好数对。

输入:
第一行一个正整数 N N N(1<= N N N<=1000000)。

接下来 N N N行,每行一个正整数,范围在1到1018之间。 N N N个数中任意两个数都是不同的。

输出:
只有一行一个整数,表示友好数对的个数。

样例:
纪中 Day15&Day16_第3张图片解题思路:
利用二进制存储
再转为十进制, f f f[ y y y]++
进行&位运算
如果结果不为0
说明有相同的位
a n s ans ans= a n s ans ans+ f f f[ i i i] * f f f[ j j j];
最后 a n s ans ans= a n s ans ans+ f f f[ i i i] * ( f f f[ i i i]-1)
因为不一样的数有相同的数,可能转成同一个二进制
自己也要乘自己

代码:

#include
#include
using namespace std;
long long n,x,ans,c;
long f[1200];
int main()
{
	freopen("kompici.in","r",stdin);
	freopen("kompici.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf("%lld",&x); 
		int y=0,c=0;
		while (x>0)
		{
			  c=x%10;
			  x=x/10;
			  y=y|(1<<c); //利用二进制存储,<<左移
		}
		f[y]++;  //标记
	}
	for (int i=1;i<=1023;i++)
	{
	    if (f[i]==0) continue;  //没有数,就不用做
	    for (int j=1;j<=1023;j++)
	    { 
	    	if ((i&j)&&(i!=j))  //不相等且i和j有相同的位
	    	   ans=ans+f[i]*f[j]; 
		}
		ans=ans+f[i]*(f[i]-1); 
	}
	printf("%lld\n",ans/2);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

你可能感兴趣的:(纪中)