2019.11.24 摸底测试补题报告

2019.11.24 第一次摸底补题报告

A. Water

题目描述:
有n个容量不一的瓶子,现在想往瓶子里装水,但是一个一个装太累了。于是为了不那么累,就只好佛系装水了。规则就是每次随机选中一个瓶子,往该瓶子里装水,若该瓶子里水满了,就找到下一个瓶子,直至找到最后一个瓶子。现在想知道,经过m次随机操作后,每个瓶子里有多少水。

输入:
一个整数t(1≤t≤10),代表t组数据
每组数据输入一个n和m,代表瓶子数和操作数(1≤n,m≤105)
接下来一行n个整数,代表每个瓶子的容量(≤109)
接下来m行每行2个数x和y代表往第x个瓶子里装y升的水(1≤x≤n,1≤y≤109)

输出:
对于每组输出n个数。

样例输入:

1
7 4
3 4 5 5 6 7 8
3 3
1 8
5 6
6 9

样例输出:

3 4 4 0 6 7 2

自己的题解:先建一个数组给代表瓶子的容量,再给瓶子装水,水满了就继续装下一个瓶子,更新瓶子的容量就行。

以下是代码:

#include 
#include  
using namespace std;

long long int b[100005]; 	//一开始没用long long 导致报错。
long long int a[100005];

int main () {
	int t;
	cin >> t;
	while (t--) {
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		int n, m, x, y;
		cin >> n >> m;
		for (int i = 1; i <= n; i++) {
			cin >> a[i];
		}
		for (int i = 1; i <= m; i++) {
			cin >> x >> y;
			if (b[x] == 0) {
				b[x] = y;
			} else {
				b[x] = b[x] + y;
			}
		}
		for (int i = 1; i <= n; i++) {
			if(b[i] > a[i]) {
				b[i + 1] = b[i + 1] + b[i] - a[i];
				b[i] = a[i];
			} 
		}
		for (int i = 1; i <= n; i++) {
			if(i == n) {
				cout << b[i];
			} else {
				cout << b[i] << " ";
			}
				
		}
		cout << endl;
	}
	return 0;
}

B. Prime Split

题目描述:
给定一个整数n,能不能将其分解为三个素数之和,有多少种分法。
例如7=2+2+3,注:(2,2,3),(2,3,2)为同一种

输入:
第一行一个整数t,(1≤t≤10)
接下来t行,每行一个整数n,(1≤n≤4∗104)

输出:
对于每一整数n输出一个数字

样例输入:

3
4
5
9

样例输出:

1
1
2

自己的题解:用Prime数组存储1~40000里面的素数,再从里面进行选择,因为已经拍好循了,就只用保证循环从前面的一个数开始。
(一开始用了3个for循环导致报错,经提醒第三个数可表示为 n-prime[i]-prime[j]。多谢大佬们)

以下是代码:

#include 
using namespace std;
int Prime[6000];
int C[400005];

bool prime(int x)
{
	int i;
	for(i = 2; i * i <= x; i++)
	{
		if(x % i == 0)
		return false;
	}
	return true;
}

int main ()
{
	int count = 0;
	for(int i = 2; i <= 40000; i++)
	{
		if(prime(i))
		{
			Prime[++count] = i;
			C[i] = 1;
		}
		
	}
	int t, n;
	cin >> t;
	while(t--)
	{
		int z;
		int num = 0;
		cin >> n;
		for(int i = 1; i <= n; i++)
		{
			if(Prime[i] > n)
			break;
			else
			{
				for(int j = i; j <= n; j++)
				{
					if(Prime[j] + Prime[i] > n)
					break;
					else
					{
						z = n - Prime[i] - Prime[j];
						if(C[z] == 1 && z >= Prime[j])
						{
							num++;
						}		
					}
				}
			}
		}
		cout << num << endl;
	}
}

C. connnect

题目描述:
有n个顶点,每个顶点有自己的坐标(Xi,Yi,Zi),现在想把这n个顶点连接起来,已知连接两个顶点u和v的花费是 MIN(|Xu−Xv|,|Yu−Yv|,|Zu−Zv|)。现在,请花费最小的代价把这些点连接起来

输入:
第一行输入一个整数n (1≤n≤2∗105)
接下来n行,第i行包含3个整数Xi,Yi和Zi(|Xi|,|Yi|,|Zi|≤109),代表第i个点的坐标,数据保证不会有任意两个点的坐标相同

输出:
输出最小代价。

样例输入:

3
1 1 1
2 3 4
5 5 5

样例输出:

2

自己太菜,提醒过是最小生成树的算法,但是完全不会应用到上面。下次补上(记!!!!!!)

D. K-nary

题目描述:
众所周知。固定长度的K进制可以表达的范围是固定的。小O最近就迷上了进制数,但是小O不喜欢进制数里相邻两位的数字太相近。因此小O想知道满足这样条件的进制数有多少。
首先,这个进制数必须是N位长度的K进制数,并且满足任意相邻的两位数字之差的绝对值大于C

输入:
首先一个数字t(1≤10≤t),代表多组输入
接下来t行,每行3个数字N,K,C(1≤N≤103, 2≤K≤103, 0≤C≤min(K−2,10))

输出:
对于每组数据输出一个整数,这个数可能十分大,将结果对109+7取模。

样例输入:

1
2 4 1

样例输出:

4

没怎么学过的动态规划。学了再补

E. Number

题目描述:
给出一个整数n,将其分解为若干个正整数之和,使得这些正整数的乘积x最大,
然后请你计算1nmod x。(测试数据保证n与x互质)

输入:
一个整数N(5≤n≤59)

输出:
1nmod x的值

样例输入:

7

样例输出:

7

自己的题解:求乘积x是有规律的,如下:

2019.11.24 摸底测试补题报告_第1张图片

 可见我们只需一直循环这个n就行,n跳出来的条件为(n<4)
 最后只需要乘以循环i的3加上最后的数就行。
 取模的内容用上了扩展欧几里得算法(虽然我还得再看一下(ㄒoㄒ))

以下是代码:

#include 
using namespace std; 
#define ll long long
 void ex_gcd(ll a,ll b,ll &x,ll &y){
    if(!b)
    { 
    	x=1,y=0; return ;
    }
    ex_gcd(b,a%b,x,y);
    ll t=x; x=y,y=t-(a/b)*y;
 }

 inline ll inv(ll a,ll mod){
    ll inv_a,y;
    ex_gcd(a,mod,inv_a,y);
    return (inv_a%mod+mod)%mod;
 }
 
int main()
{
	int n;
	ll mod = 1;
	ll sum = 0;
	cin >> n;
	int i = n;
	while (n>4) {
		n = n - 3;
		mod = mod * 3;
	}
	mod = mod * n;
	sum = inv(i,mod);
	cout << sum << endl;
	return 0;
}

F. 操作数

题目描述:
现在n个数m个操作,初始化时每个数都是0,现有两个操作
1 L R将[L,R]区间内的数反转,将1变成0,0变成1
2 X 查询第x个数是0还是1

输入:
第一行输入n和m。(1≤n≤105,1≤m≤105)
接下来m行,每行的第一个数t表示操作的类型
若t = 1,则接下来有两个数L和R,表示将[L,R]区间的数反转
若t = 2,则接下来有一个数i,表示第i个数的值。(1≤L,R,i≤n)

输出:
对于每一个t=2的操作,输出对应的答案。

样例输入:

20 10
1 1 10
2 6
2 12
1 5 12
2 6
2 15
1 6 16
1 11 17
2 12
2 6

样例输出:

1
0
0
0
1
1

自己的题解:一开始用了两个for循环,时间超时。后来学了一下线段树。区间赋值和区间查找就很快了

以下是代码:

#include 
using namespace std;
const int MAX = 100004;

int Lazy[MAX * 4];
int Tree[MAX * 4]; 

void PushDown(int root)
{
	Lazy[root * 2] = Lazy[root] + Lazy[root * 2];
	Lazy[root * 2 + 1] = Lazy[root] + Lazy[root * 2 + 1];
	Tree[root * 2] = Tree[root * 2] + Lazy[root];
	Tree[root * 2 + 1] = Tree[root * 2 + 1] + Lazy[root];
	Lazy[root] = 0;
}

void query(int root, int nstart, int nend, int x)
{
	int Z;
	if(x < nstart || x > nend)
	return;
	if(nstart == nend)
	{
		if(Tree[root] %2 != 0)
		cout << "1" << endl;
		else
		cout << "0" << endl;
		return;
	}
	if(Lazy[root])
	PushDown(root);
	int mid = (nstart + nend)/2;
	if(mid >= x)
	query(root*2, nstart, mid, x);
	if(mid < x)
	query(root*2+1, mid+1, nend, x);
}

void update(int root, int nstart, int nend, int l, int r)
{
	if(l > nend || r < nstart) 
	return;
	if(l <= nstart && r >= nend) 
	{
		Lazy[root]++;
		Tree[root]++;
		return;
	}
	if(Lazy[root])
	    PushDown(root);
	int mid = (nstart + nend)/2;
	if(mid >= l)
	update(root*2, nstart, mid, l, r);
	if(mid < r)
	update(root*2+1, mid+1, nend, l, r);
}

int main() 
{
	int n, m, X, L, R, Z, P;
	cin >> n >> m;
	for(int i = 1; i <= m; i++)
	{
		cin >> X;
		if(X == 1)
		{
			cin >> L >> R;
			if(L > R)
			{
				int z = L;
				L = R;
				R = z;
			}
			update(1, 1, n, L, R);
		}
		if(X == 2)
		{
			cin >> P;
			query(1, 1, n, P);
		}
	}
	return 0;
}

G. 聚会

题目描述:
有n个人,现在有一个聚会,每个人都可以选择参加或者不参加。而参加的人中每个人要么只去送礼物,要么只接受礼物。不存在全部都接受礼物或者全部都送礼物的情况(这样要么没人送礼物,要么没人接受礼物了)。问有多少中情况?

输入:
第一行输出n,表示总共的人数。(1≤n≤105)

输出:
输出总共的数量。由于数字很大,对10的9次方+7取模。

样例输入:

3

样例输出:

12

自己的题解:公式写出来可以展开为幂指数向剪。以为这里幂太大,可以采用快速幂。

2019.11.24 摸底测试补题报告_第2张图片

以下是代码:

#include 
#define LL long long
using namespace std;
const long long int mod=1e9+7;

long long poww(long long int a, long long int b) //快速幂
{
	long long int sum = 1;
	while(b)
	{
		if(b&1)
		{
			sum = sum % mod * a % mod;
		}
		a = a % mod * a % mod;
		b >>= 1;
	}
	return sum;
}

int main()
{
	int n;
	cin >> n;
	//while(cin >> n)
//	{
	long long int A = 0;
	long long int B = 0;
	long long int SUM = 0;
	A = poww(3,n);
	B = poww(2,n + 1);
	//cout << A << " " << B << endl;
	if(A < B)
	SUM = (A + mod - B) % mod + 1;
	else
	SUM = (A % mod - B % mod) + 1; 
	cout << SUM << endl;
//}
	return 0;
}

H. 地图

题目描述:
现在有两个相同大小的地图,左上角为起点,右下角问终点。问是否存在同一条最短路径。最短距离一样,他们走的路径也一样。

输入:
第一行输入n和m。表示nm网络大小的地图。(1≤n,m≤500)
接下来2
n行,每行m个字符。表示可以通,#表示不能通。
前n行是第一个地图,后n行是第二个地图。保证左上角和右下角都是

输出:
如果存在相同的最短路径。则输出YES,否则输出NO

样例输入:
2019.11.24 摸底测试补题报告_第3张图片

样例输出:

NO

好像是找两个地图的最短路径,再把两个图和起来找最短路径。但我还没写出来

你可能感兴趣的:(ACM)