week14

文章包含了多个算法问题的描述和示例输入输出,包括网格路径计数、最大和上升子序列、数字加一操作、跳跃问题、异或和或的判断、出栈序列的构建、序列维护以及网格和数组的正确性判断。每个问题都提供了输入格式、输出格式以及部分解决方案代码片段。
摘要由CSDN通过智能技术生成

路径计数

 附加文件 统计

有一个n×n的网格,有些格子是可以通行的,有些格子是障碍。

一开始你在左上角的位置,你可以每一步往下或者往右走,问有多少种走到右下角的方案。

由于答案很大,输出对10e9+7取模的结果。

输入格式

第一行一个正整数n。

接下来n行,每行n个正整数,1表示可以通行,0表示不能通行。

输出格式

一个整数,表示答案。

样例输入

3
1 1 1
1 0 1
1 1 1

样例输出

2

数据规模

对于100%的数据,保证2≤n≤100,左上角右下角都是可以通行的。

 

#include<bits/stdc++.h>
using namespace std;
int n,mm[105][105],dp[105][105];
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&mm[i][j]);
        }
    }
    dp[1][1]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(mm[i][j])
            {
                dp[i][j]+=dp[i-1][j]+dp[i][j-1];
            }
        }
    }
    cout<<dp[n][n];
}

最大和上升子序列

 附加文件 统计

给定一个长度为 n 的数组 a1,a2,…,an,问其中的和最大的上升子序列。也就是说,我们要找到数组 p1,p2,…,pm,满足 1≤p1<p2<⋯<pm≤n 并且 ap1<ap2<⋯<apm,使得ap1+ap2+⋯+apm最大。

输入格式

第一行一个数字 n。

接下来一行 n 个整数 a1,a2,…,an。

输出格式

一个数,表示答案。

样例输入

6
3 7 4 2 6 8

样例输出

21

数据规模

所有数据保证 1≤n≤1000,1≤ai≤10e5。

#include<bits/stdc++.h>
using namespace std;
int n,a[1005],nn,ans,M=0;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        if(x>M)
        {
            nn++;
            a[nn]=x;
            M=x;
        }
        else
        {
            for(int j=1;j<nn;j++)
            {
                if(a[j]<x&&a[j+1]>x)
                {
                    a[j]=x;
                    break;
                }
            }
        }
    }
    for(int i=1;i<=nn;i++)ans+=a[i];
    cout<<ans;
}

加一

 附加文件 统计

给定一个整数 n。你需要对它做 m次操作。在一次操作中,你要将这个数的每一位 d替换成 d+1。比如,1912在进行一次操作后将变成 21023。

请求出整数 n 进行了 m次操作后的长度。答案可能很大,输出对 10e9+7取模后的结果。

输入格式

​ 第一行一个整数 t,表示测试单元的个数。

​ 接下来 t行,每行有两个整数 n和 m,表示最初的数字和进行多少次操作。

输出格式

​ 对于每个测试单元输出最终数字的长度,答案对 10e9+7取模。

样例输入

5
1912 1
5 6
999 1
88 2
12 100

样例输出

5
2
6
4
2115

数据规模

​ 所有数据保证 1≤t≤2⋅10e5,1≤n≤10e9,1≤m≤2⋅10e5。

#include<bits/stdc++.h>
using namespace std;
const int ddd=1000000007; 
int t,m,a[10],N[10],b[10];
string n;
int main()
{
    cin>>t;
    for(int i=1;i<=t;i++)
    {
    	for(int j=0;j<=9;j++)
		{
			a[j]=0;
			N[j]=0;
		} 
    	cin>>n>>m;
    	for(int j=0;j<n.size();j++)
    	{
    		a[(int)n[j]-(int)'0']++;
		}
		for(int k=0;k<=9;k++)
		{
			for(int jj=0;jj<=9;jj++)
			{
				b[jj]=(jj==k?1:0);
			}
			for(int jj=1;jj<=m;jj++)
			{
				int t=b[9];
				for(int ii=9;ii>0;ii--)
				{
					b[ii]=b[ii-1];
				}
				b[0]=t%ddd;
				b[1]=(b[1]+t)%ddd;
				
			}
			for(int l=0;l<=9;l++)
			{
				N[k]=(b[l]+N[k])%ddd;
			}
		}
		long long ans=0;
		for(int i=0;i<=9;i++)ans=(a[i]*N[i]+ans)%ddd;
		cout<<ans<<"\n";
	}
}

 

跳跳

 附加文件 统计

平面上给定了一些整点(横纵坐标均为整数的点),被称为 “魔法阵”。魔法少女派派想要在各魔法阵之间传送,每一次传送,她将使用下面的方式:

  1. 刚开始,派派已经位于某传送阵之上;
  2. 如果派派掌握一种魔法 (A,B),其中 A,B 均为整数。使用一次这个魔法可以让派派从任意整点 (X,Y)瞬间移动至 (X+A,Y+B);
  3. 选择一种魔法并开始传送,在一次传送过程中可以使用多次该魔法,但在抵达下一个传送阵之前仅能使用这一种魔法

问派派至少需要掌握多少种魔法,才能在从任意魔法阵直接传送到任意魔法阵?

输入格式

第一行一个整数 N。

接下来一行 N行,每行包含两个整数 Xi,Yi, 表示每个魔法阵的坐标。

输出格式

一个数,表示答案。

样例1输入

3
1 1
4 5
1 4

样例1输出

6

解释: 任务是从 (1,1) 传送至 (4,5)以及 (1,4) 、从 (4,5) 传送至 (1,1)以及 (1,4) 、从 (1,4) 传送至 (1,1) 以及 (4,5) 。

注意你不能使用 (0,3)+(3,1)的魔法从 (1,1) 到达 (4,5)。因为每次移动,你只能使用一种魔法。

当然,你可以学习 (0,1),那样的话,从 (1,1) 到达 (1,4) 则需要使用 3 次 (0,1) 魔法了。

样例2输入

3
1 1
2 2
1000000000 1000000000

样例2输出

2

数据规模

  • N∈[10,500]
  • Xi,Yi∈[0,10e9], 但保证坐标之间两两不同
#include<bits/stdc++.h>
using namespace std;
int N;
struct node
{
	int x,y;
}n[505];
set<double>s;
bool cmp(node a,node b)
{
	return a.y>b.y;
}
int main()
{
	cin>>N;
	for(int i=1;i<=N;i++)cin>>n[i].x>>n[i].y;
	sort(n+1,n+N+1,cmp);
	for(int i=1;i<=N;i++)
	{
		for(int j=1;j<i;j++)
		{
			double t=((n[i].y-n[j].y)*1.0)/((n[i].x-n[j].x)*1.0);
			s.insert(t);
		}
	}
	int ans=s.size()*2;
	cout<<ans;
}

 

异或和或

 附加文件 统计

对于一个长度为 n�的01序列 a1,a2,…,an。

你可以执行以下操作任意多次:

  • 选择两个下标 1≤i,j≤n(i≠j)。

  • 记x=ai xor aj, y=ai or aj, 其中 xor 表示按位异或 , or 表示按位或。

  • 然后令 ai=x,aj=y 或 ai=y,aj=x。

给定两个01序列 s,t, 请你判断是否可以通过有限次(可以为0次)操作将序列 s 变为 t。

输入格式

第一行一个整数 t , 表示数据的组数(1≤t≤103)。接下来 t 组数据:

每组第一行一个01字符串 s(1≤|s|≤103),每组第二行一个01字符串 t(1≤|t|≤103)。

注意:|s| 可能不等于 |t|。

输出格式

如果可以通过有限次(可以为0次)操作将序列 s 变为 t , 输出 YES , 否则输出 NO

样例输入

2
001
011
11
101

样例输出

YES
NO

样例解释

第一组数据选择 i=2,j=3 , 那么 x=1,y=1 , 接着令 ai=x,aj=y即可得到 t 序列。

第二组数据 |s|=2,|t|=3 显然无法满足要求。

#include<bits/stdc++.h>
using namespace std;
long long k,d[1000005],ans,f[1000005],S,l,cnt,dd;
void read()
{
	d[0]=1;
	scanf("%lld",&k);
	getchar();
	long long t=getchar();
	while(t=='1'||t=='0')
	{
		S++;
		cnt+=t-'0';
		f[S]=cnt;
		d[cnt]++;
		t=getchar();
	}
}
int main()
{
	read();
	if(k==0)
	{
		for(long long i=0;i<=S;i++)
		{
			if(i>=1&&f[i-1]==f[i-2]&&dd>=1)
			{
				dd--;
				ans+=dd;
				continue;
			}
			dd=0;
			for(long long j=i+1;j<=S;j++)
			{
				long long t=f[j]-f[i];
				if(t==k)
				{
					ans++;
					dd++;
				}
				else if(t>k)break;
			}
		}
	}
	else 
	{
		for(long long i=k;i<=cnt;i++)
		{
			ans+=d[i]*d[i-k];
		}
	}
		
	printf("%lld",ans);
}

 

出栈序列判断

 附加文件 统计

现在有一个栈,有 n 个元素,分别为 1,2,…。我们可以通过 push 和 pop 操作,将这 n 个元素依次放入栈中,然后从栈中弹出,依次把出栈的元素写下来得到的序列就是出栈序列。

比如 n=3,如果执行 push 1, push 2, pop, push 3, pop, pop,那么我们 pop 操作得到的元素依次是 2,3,1。也就是说出栈序列就是 2,3,1。

现在给定一个合法的出栈序列,请输出一个合法的由 push 和 pop 操作构成的操作序列。这里要求 push 操作一定是按 1,2,…,n 的顺序。

输入格式

第一行一个整数 n。接下来一行 n 个整数,表示出栈序列。

输出格式

输出 2n行,每行一个 push 或 pop 操作,可以证明一个出栈序列对应的操作序列是唯一的。

样例输入1

3
2 3 1

样例输出1

push 1
push 2
pop
push 3
pop
pop

样例输入2

5
1 3 5 4 2

样例输出2

push 1
pop
push 2
push 3
pop
push 4
push 5
pop
pop
pop

数据规模

对于 100% 的数据,保证 1≤n≤100000,输入一定是个合法的出栈序列。

#include<bits/stdc++.h>
using namespace std;
int n,a,t=0;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a);
		while(a>t)
		{
			t++;
			printf("push %d\n",t);
		}
		printf("pop\n");
	}
}

 

#57. 序列维护

 附加文件 统计

你有一个序列,现在你要支持几种操作:

  • insert x y,在从前往后的第x个元素后面插入y这个数。如果x=0,那么就在开头插入。

  • delete x,删除从前往后的第x个元素。

  • query k,询问从前往后数第k个元素是多少。

输入格式

第一行一个整数m,表示操作个数。

接下来m行,每行一个上面所述的操作。

输出格式

输出若干行,对于每个查询操作,输出答案。

样例输入

10
insert 0 1
insert 1 2
query 1
query 2
insert 0 3
query 1
delete 1
query 1
insert 1 4 
query 2

样例输出

1
2
3
1
4

数据规模

对于100%的数据,保证m≤10e3。

对于insert操作,保证1≤y≤10e9。

对于所有操作,保证位置不会超出当前序列的长度。

#include<bits/stdc++.h>
using namespace std;
int n;
struct node
{
	int v;
	node* next;
}N[1005];
int main()
{
	N[0].v=0;
	N[0].next=N+1003;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		string s;
		int a,b;
		cin>>s>>a;
		if(s=="insert")
		{
			node* p=N;
			for(int j=1;j<=a;j++)
			{
				p=p->next;
			}
			N[i].next=p->next;
			p->next=N+i;
			cin>>N[i].v;
		}
		else if(s=="delete")
		{
			node* p=N;
			for(int j=1;j<a;j++)
			{
				p=p->next;
			}
			p->next=p->next->next;
		}
		else
		{
			node* p=N;
			for(int j=1;j<=a;j++)
			{
				p=p->next;
			}
			cout<<p->v<<endl;
		}
	}
}

 

#551. 网格判断

 附加文件 统计

您将获得一个 n×n 的网格,网格中每个正方形的颜色为黑色或白色。如果满足以下所有条件,则网格是正确的:

  • 每行的黑色方块数与白色方块数相同。

  • 每列的黑色正方形数与白色方块数相同。

  • 没有行或列具有 3个及以上相同颜色的连续正方形。

给定网格,确定它是否正确。

输入格式

第一行一个数字 n(2≤n≤24), 并且数字 n 是偶数。

接下来 n行,每行包含一个长度为n的由字符BW组成的字符串,代表网格正方形的颜色。

输出格式

如果网格正确,请打印数字 1 在一行上。否则,请打印数字 0 在一行上。

样例输入

4
WBBW
WBWB
BWWB
BWBW

样例输出

1
#include<bits/stdc++.h>
using namespace std;
int n,h[25],l[25];
int read()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		getchar();
		for(int j=1;j<=n;j++)
		{
			int t=getchar();
			if(t=='W')
			{
				h[i]++;
				l[j]++;
			}
		}
	}
	for(int i=2;i<=n;i++)
	{
		if((h[i]!=h[i-1])||(l[i]!=l[i-1]))return 0;
	}
	return 1;
}
int main()
{
	cout<<(read());
}

 

#554. 整齐的数组

 附加文件 统计

​ Polycarp 有一个长度为 n的数组 a1,a2,...,an(n 是偶数)。Polycarp 还得到了一个正整数 k,他开始对数组 a做如下操作:选择一个下标 i (1≤i≤n)使 ai减去 k。

​ 在 Polycarp 进行若干次操作后(可能 0 次),数组 a 中的所有数都变成相同的了。请你找到最大的符合要求的 k,如果 k 可以为任意大,请输出 −1。

输入格式

​ 第一行一个整数 t,表示测试单元的个数。

​ 接下来每个测试单元有两行。第一行包含一个偶数 n。第二行包含 n 个整数 a1,a2,...,an。

输出格式

​ 对于每个测试单元输出单独一行一个整数 k (k≥1) —— Polycarp 能用来对数组进行操作的最大的数,或者 −1 —— 如果 k 能任意大的话。

样例输入

3
6
1 5 3 1 1 5
8
-1 0 1 -1 0 1 -1 0
4
100 -1000 -1000 -1000

样例输出

2
1
1100

数据规模

​ 所有数据保证 1≤t≤10,4≤n≤40(n 是偶数),−10e6≤ai≤10e6,并且 n 的总和不超过100。

#include <bits/stdc++.h>
using namespace std;
int a[45],n,t,k,ans;
int gcd(int p,int q)
{
	return q>0?gcd(q,p%q):p;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		ans=0;
		scanf("%d",&t);
		for(int i=1;i<=t;i++)
		{
			scanf("%d",&a[i]);
		}
		sort(a+1,a+t+1);
		for(int i=1;i<=t-1;i++)
		{
			for(int j=i+1;j<=t;j++)
			{
				if(ans==0)ans=a[j]-a[i];
				else ans=gcd(ans,a[j]-a[i]);
			}
		}
		if(ans==0)ans=-1;
		printf("%d\n",ans);
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值