蓝桥杯练习

兰顿蚂蚁

题目链接:https://www.dotcpp.com/oj/problem1429.html
思路:
1)首先定义一个字符串数组dir[4] = {‘U’,‘L’,‘D’,‘R’},ULDR顺序不能改变,假设当前头朝向为dir[x],然后我们可以发现向右转后,头朝向为dir[(x+3)%4],向右转后,头朝向为dir[(x+1)%4].
2) 找到规律后,我们用一个结构体来保存头朝不同方向左右转后的头朝方向。
3)之后可以找出k步之后的位置。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <time.h>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;

//srand(time(NULL));
//      m = rand() % 10 + 1;
//      cout << m;
struct node{
	int dir1[2][2];
	char s;
}node[4];

int a[105][105];
char dir[4] = {'U','L','D','R'};

void init()
{
	node[0].s = 'U';
	node[0].dir1[0][0] = 0;
	node[0].dir1[0][1] = -1;
	node[0].dir1[1][0] = 0;
	node[0].dir1[1][1] = 1;
	node[1].s = 'L';
	node[1].dir1[0][0] = 1;
	node[1].dir1[0][1] = 0;
	node[1].dir1[1][0] = -1;
	node[1].dir1[1][1] = 0;
	node[2].s = 'D';
	node[2].dir1[0][0] = 0;
	node[2].dir1[0][1] = 1;
	node[2].dir1[1][0] = 0;
	node[2].dir1[1][1] = -1;
	node[3].s = 'R';
	node[3].dir1[0][0] = -1;
	node[3].dir1[0][1] = 0;
	node[3].dir1[1][0] = 1;
	node[3].dir1[1][1] = 0;
}

int main()
{
	int n,m,x,y,k,r,l;
	char s;
	scanf("%d%d",&n,&m);
	for(int i = 0; i < n; i++){
		for(int j = 0; j < m; j++){
			scanf("%d",&a[i][j]);
		}
	}
	scanf("%d%d %c%d",&x,&y,&s,&k);
	int xb;
	init();
	while(k--){
		for(int i = 0; i < 4; i++){
			if(s == node[i].s){
				xb = i;
			}
		}
		if(a[x][y] == 0){
			a[x][y] = 1;
			x += node[xb].dir1[0][0];
			y += node[xb].dir1[0][1];
			xb = (xb + 1) % 4;
			s = node[xb].s;
		}
		else{
			a[x][y] = 0;
			x += node[xb].dir1[1][0];
			y += node[xb].dir1[1][1];
			xb = (xb + 3) % 4;
			s = node[xb].s;
		}
		//cout << x << " " << y << " " << s <<  endl;
	}
	printf("%d %d\n",x,y);
    return 0;
}

幸运数

题目链接:https://www.dotcpp.com/oj/problem1441.html
思路:
1)直接暴力,题目要我们求m-n里面的幸运数个数,那么我们只要求1-n里面的有几个幸运数,n之后的不用管。
2)如何保存幸运数呢,我们先初始化一个数组,直接在这个数组上进行操作,因为我们删除的是以某个幸运数的倍数作为下标的幸运数,删除后靠在一起,实际上也就是删第某个幸运数的倍数的幸运数,那么我们每次去遍历看看这是第几个幸运数,如果能整除,便置为零。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <time.h>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;

//srand(time(NULL));
//      m = rand() % 10 + 1;
//      cout << m;

int a[1000005];
int main()
{
	for(int i = 1; i <= 1000000; i++) a[i] = i;
	int m,n;
	scanf("%d%d",&m,&n);
	int t = 2;
	while(t <= n){
		int cnt = 0;
		for(int i = 1; i <= n; i++) {
			if(a[i]) cnt++;
			if(cnt % t == 0) a[i] = 0;
		}
		t++;
		while(a[t] == 0) t++;
	}
	int ans = 0;
	for(int i = m + 1; i < n; i++){
		if(a[i]) ans++;
	}
	printf("%d\n",ans);
}

最大子阵:dp

题目戳我

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <time.h>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;

//srand(time(NULL));
//      m = rand() % 10 + 1;
//      cout << m;

ll dp[505];
ll get_max(ll sum[],int m)
{
	ll ans = -ds;
	for(int i = 0; i < m; i++){
		dp[i] = max(dp[i-1] + sum[i],sum[i]);
	}
	for(int i = 0; i < m; i++){
		ans = max(ans,dp[i]);
	}
	return ans;
}

ll sum[505],a[505][505];
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i = 0; i < n; i++)
		for(int j = 0; j < m; j++) 
		    scanf("%lld",&a[i][j]);
	ll ans = -ds;
	for(int i = 0; i < n; i++){
		memset(sum,0,sizeof sum);
		for(int j = i; j < n; j++){
			for(int k = 0; k < m; k++){
				sum[k] += a[j][k];
			}
			ll temp = get_max(sum,m);
			ans = max(temp,ans);
		}
	}
	printf("%lld",ans);
}

蚂蚁感冒

https://www.dotcpp.com/oj/problem1454.html
思路:先保存第一个蚂蚁的位置,然后按绝对值大小堆每个蚂蚁的位置排个序,然后找到第一个生病的蚂蚁的位置记为xb,同时l_sum[i]算出1-i中向左的蚂蚁的个数,r_sum[i]算出1-i中向右的蚂蚁的个数,然后利用这两个前缀和算出与这个生病蚂蚁方向相反的蚂蚁个数。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <time.h>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;

//srand(time(NULL));
//      m = rand() % 10 + 1;
//      cout << m;

bool cmp(int m,int n)
{
	return abs(m) < abs(n);
}

int a[55],l_sum[55],r_sum[55];
int main()
{
	int n,xb,t;
	scanf("%d",&n);
	for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
	t = a[1];
	sort(a+1,a+n+1,cmp);
	for(int i = 1; i <= n; i++){
		if(a[i] == t) xb = i;
		l_sum[i] = l_sum[i - 1] + (a[i] < 0 ? 1 : 0);
		r_sum[i] = r_sum[i - 1] + (a[i] > 0 ? 1 : 0);
	}
	//cout << l_sum[2];
	int ans = 0;
	if(t < 0){
		ans = r_sum[xb - 1];
		ans += l_sum[n] - l_sum[xb];
	}
	else {
		ans = l_sum[n] - l_sum[xb];
		ans += r_sum[xb - 1];
	}
	printf("%d\n",ans+1);
}

连号区间数

https://www.dotcpp.com/oj/problem1456.html
**思路:**因为是一个连续区间,那么这个区间的最大值-最小值一定要等于这个区间内元素的个数,那么我们遍历数组里的每个数,然后查找每个数后面数的最大最小值,作下上面的判断便可找出所有成立的区间。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <time.h>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;

//srand(time(NULL));
//      m = rand() % 10 + 1;
//      cout << m;

int main()
{
	int n,a[500005];
	scanf("%d",&n);
	ll ans = 0;
	int mmax = 0,mmin = 50005;
	for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
	for(int i = 1; i <= n; i++){
		mmax = mmin = a[i];
		for(int j = i; j <= n; j++){//对a[i]后面的每个数作下判断,看这个区间是否符合条件。
			mmax = max(a[j],mmax);
			mmin = min(a[j],mmin);
			if(mmax - mmin == j - i) ans++;
		}
	}
	printf("%lld",ans);
}

2n皇后问题

https://www.dotcpp.com/oj/problem1460.html
思路:
先来看看n皇后问题求解方法 传送门
1)知道n皇后问题的求解方法后,这道题就算是一道模板题。
2)我们考虑先放白皇后,放完白皇后后,再放黑皇后。
3)具体看代码。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <time.h>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;

//srand(time(NULL));
//      m = rand() % 10 + 1;
//      cout << m;

int n,w_col[10] = {0},b_col[10] = {0},a[10][10];
int cnt = 0;

bool w_check(int r,int c)
{
	if(b_col[r] == c || a[r][c] == 0) return false;//如果这个点为零或者这一行已经放了白皇后,那么就不能放
	for(int i = 1; i < r; i++)
	    if(w_col[i] == c || (abs(i - r) == abs(w_col[i] - c)))//如果第i行所放的黑皇后在第c列,或者第i行的黑皇后在这个点在同一对角线那么也不能放。
	        return false;
    return true;
}

bool b_check(int r,int c)
{
	if(a[r][c] == 0) return false;
	for(int i = 1; i < r; i++)
	    if(b_col[i] == c || (abs(i - r) == abs(b_col[i] - c)))//意思同上。
	        return false;
    return true;
}

void w_dfs(int x)
{
	//cout << x;
	if(x > n){
		cnt++;//两个皇后都放完后,是一个方法。
		return;
	}
	for(int i = 1; i <= n; i++){
		if(w_check(x,i)){
			w_col[x] = i;
			w_dfs(x+1);//考虑下一行。
		}
	}
}

void b_dfs(int x)
{
	//cout <<x;
	if(x > n){
		w_dfs(1);//白皇后放完后,继续放黑皇后。
		return;
	}
	//cout << x << endl;
	for(int i = 1; i <= n; i++){
		if(b_check(x,i)){
			b_col[x] = i;
			b_dfs(x+1);//考虑下一行。
		}
	}
}

int main()
{
	scanf("%d",&n);
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			scanf("%d",&a[i][j]);
		}
	}
	b_dfs(1);
	printf("%d\n",cnt);
}

核桃的数量

题目链接:https://www.dotcpp.com/oj/problem1446.html
**思路:**因为每个组的数量都要相等,并且组内的每个人获得的数量都要相等,也就是说每个组得到的核桃数量要能被每个组的人数整除,并且要求最少,实际上也就是求每个组人数的最小公倍数。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <time.h>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;

//srand(time(NULL));
//      m = rand() % 10 + 1;
//      cout << m;


int main()
{
	int a,b,c;
	scanf("%d%d%d",&a,&b,&c);
	int t1,t2;
	t1 = __gcd(a,b);
	t1 = a/t1*b;
	t2 = __gcd(t1,c);
	t2 = t1/t2*c;
	printf("%d\n",t2);
}

完美的代价:贪心

题目:https://www.dotcpp.com/oj/problem1467.html
思路:回文串顾名思义就是从左往右读和从右往左读都是一样的,而现在问的是让一个串变成回文串的最少交换次数,那么我先保持左边的元素不动,从后面往前面找第一个与这个元素相同的位置,把它交换的与这个元素对称的位置上去,如果这俩个元素在同一个位置但是串的长度为偶数,那么一定不可能变成回文串,但如果是奇数的话,这种情况也只能出现一个,这个元素最终会换到串的中间去,例如:aabaa.

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <time.h>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;

//srand(time(NULL));
//      m = rand() % 10 + 1;
//      cout << m;


int main()
{
	char s[8005];
	int n,l,flag = 0;
	scanf("%d",&n);
	scanf("%s",s);
	l = n - 1;
	int cnt = 0;
	for(int i = 0; i < l; i++){
		for(int j = l; j >= i; j--){
			if(i == j){
				if(n % 2 == 0 || flag == 1){
			        printf("Impossible\n");
					return 0;       		
			 	}
			 	flag = 1;
			 	cnt += n / 2 - i;
			}
			else if(s[i] == s[j]){
				for(int k = j; k < l; k++){
					swap(s[k],s[k + 1]);
					cnt++;
				}
				l--;
				break;
			}
		}
	}
	printf("%d\n",cnt);
	return 0;
}

FJ的字符串

题目链接:https://www.dotcpp.com/oj/problem1461.html

#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <time.h>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;

//srand(time(NULL));
//      m = rand() % 10 + 1;
//      cout << m;


int main()
{
    string s;
    s += "A";
    int n;
    char a[1];
    cin >> n;
    for(int i = 2; i <= n; i++){
        string t;
        t = s;
        string k;
        k += (i - 1 + 'A');
        s += k;
        s += t;
    }
    cout << s;
    return 0;
}

买不到的数目:dp+数论

题目链接:https://www.dotcpp.com/oj/problem1427.html
数论:
构造方程:ax+by = c
a,b互质,最大无解的情况是 a*b-a-b
思路:
1)状态 dp[i]=1表示i能被a,b组合
2)状态转移 dp[i] = (dp[i-a]==1||dp[i-b]==1)?1:0

#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <time.h>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;

//srand(time(NULL));
//      m = rand() % 10 + 1;
//      cout << m;

int dp[1000005];
int main()
{
	int n1,n2;
    cin >> n1 >> n2;
    dp[n1] = 1;
    dp[n2] = 1;
    int n = max(n1,n2);
    for(int i = n + 1; i < 1000005; i++){
    	if(dp[i - n1] || dp[i - n2]) dp[i] = 1;
	}
	int ans;
	//cout << dp[12] << endl;
	for(int i = 1000004; i >= 0; i--){
		if(dp[i] == 0){
		    ans = i;
		    break;
		}
	}
    cout << ans;
    return 0;
}

[蓝桥杯][2019年第十届真题]修改数组

传送门
思路:直接暴力枚举的思路是先用数组b去作为访问数组,1表示出现过,0表示未出现,当去修改某个数x时,循环递增去判断x+=1是否出现,然而明显会超时。
优化:在每个数循环递增的时候,可能会多次经过某个数,假设是k次,也就是说这个数后面的k个数都是出现过的,但k个数之后的数我们还要去判断是否出现过,所有我们就直接跳到第k个数之后就够了,其中这k个数是包括这个数本身的,不能用map去存,会超时。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <time.h>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;

//srand(time(NULL));
//      m = rand() % 10 + 1;
//      cout << m;

int a[100005];
int b[100005];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i = 1; i <= n; i++){
		scanf("%d",&a[i]);
	}
	b[a[1]]++;
	for(int i = 2; i <= n; i++){
		int x = a[i];
		while(b[x]){
			int k = x;
			x += b[x];
			b[k]++;
		}
		b[x]++;
		a[i] = x;
	}
	for(int i = 1; i <= n; i++){
		if(i == 1) printf("%d",a[i]);
		else printf(" %d",a[i]);
	}
	return 0;
}

能量项链

https://www.dotcpp.com/oj/problem1255.html
思路:贪心,优先把小的合并掉,所有每次合并时只要找到当前最小的数,合并完后删除即可。

#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <time.h>
#include <stack>
#include <queue>
#include <string.h>
#include <cmath>
#include <bitset>
#include <set>
#include <map>
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const ll ds = 1e15+7;
const double p = 3.141592653589793238462643383;
using namespace std;

//srand(time(NULL));
//      m = rand() % 10 + 1;
//      cout << m;

vector<int>a;
int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 0; i < n; i++) {
    	int t;
    	scanf("%d",&t);
    	a.push_back(t);
    }
    int l;
    ll sum = 0;
    l = a.size();
    while(l != 1){
    	int mmin = a[0],xb = 0;
    	for(int j = 0; j < l; j++){
    		if(mmin > a[j]){
    			mmin = a[j];
    			xb = j;
			} 
		}
		sum += 1ll*a[xb]*a[(xb - 1 + l) % l]*a[(xb + 1) % l];
		a.erase(a.begin()+xb);
		l = a.size();
	}
    printf("%lld\n",sum);
    return 0;
}

分苹果

题目链接:https://www.dotcpp.com/oj/problem1501.html
线段树+lazy标记版:

#include <bits/stdc++.h>
#include <algorithm>
#include <cmath>
#define mod 1000000007
#define ll long long

using namespace std;

int sum[100005];
int tree[400005],lazy[400005];
void build(int l,int r,int inx)
{
    if(l == r){
    	tree[inx] = sum[l];
    	lazy[inx] = 0;
    	return;
	}
	int mid = (l + r) >> 1;
	build(l,mid,inx*2);
	build(mid+1,r,inx*2+1);
	tree[inx] = tree[inx*2] + tree[inx*2+1];
}

void pushdown(int len1,int len2,int k)
{
	lazy[k*2] += lazy[k];
	lazy[k*2+1] += lazy[k];
	tree[k*2] += lazy[k]*len1;
	tree[k*2+1] += lazy[k]*len2;
	lazy[k] = 0;
}

void update(int l,int r,int L,int R,int val,int inx)
{
	//if(l > r || L > r || R < l) return;
	if(L <= l && R >= r){
		tree[inx] += (r - l + 1)*val;
		lazy[inx] += val;
		return; 
	}
	int mid = (l + r) >> 1;
	//cout <<l << r << mid <<endl;
	pushdown(mid-l+1,r-mid,inx);
	if(l <= mid) update(l,mid,L,R,val,inx*2);
	if(r > mid) update(mid+1,r,L,R,val,inx*2+1);
	tree[inx] = tree[inx*2] + tree[inx*2+1];
}

int query(int l,int r,int L,int R,int inx)
{
	if(l > r || L > r || R < l) return 0;
	if(L <= l && R >= r){
		return tree[inx];
	}
	int mid = (l+r) >> 1;
	pushdown(mid-l+1,r-mid,inx);
	int ans = 0;
	if(l <= mid) ans += query(l,mid,L,R,inx*2);
	if(r > mid) ans += query(mid+1,r,L,R,inx*2+1);
	return ans;
}

int main()
{
	int n,m,l,r,c;
	scanf("%d%d",&n,&m);
	build(1,n,1);
	while(m--){
		scanf("%d%d%d",&l,&r,&c);
		update(1,n,l,r,c,1);
		//printf("%d\n",tree[1]);
	}
	for(int i = 1; i <= n; i++){
		printf("%d ",query(1,n,i,i,1));
	}
	//printf("%d",tree[1]);
    return 0;	
} 

差分版:

#include <bits/stdc++.h>
#include <algorithm>
#include <cmath>
#define mod 1000000007
#define ll long long

using namespace std;

int sum[100005];
int ca[100005];
int main()
{
	int n,m,l,r,c;
	scanf("%d%d",&n,&m);
	while(m--){
		scanf("%d%d%d",&l,&r,&c);
		ca[l] = ca[l] + c;
		ca[r+1] = ca[r+1] - c;
	}
	int cnt = 0;
	for(int i = 1; i <= n; i++){
		cnt += ca[i];
		sum[i] = cnt;
	}
	for(int i = 1; i <= n; i++){
		printf("%d ",sum[i]);
	}
    return 0;	
} 

打水问题

题目链接:https://www.dotcpp.com/oj/problem1523.html
贪心
思路:
1)优先让打水时间少的人先去打水,可以让后面的人等待时间少。
2)每次去找当前水龙头被使用的总时间最少的那个,将下一个人替换他,并让等待时间加上这个水龙头使用的总时间,然后再更新这个水龙头使用的总时间。

#include <bits/stdc++.h>
#include <algorithm>
#include <cmath>
#define mod 1000000007
#define ll long long

using namespace std;

int a[1005],b[1005],c[1005];
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i = 1; i <= n; i++) 
	    scanf("%d",&a[i]);
	sort(a+1,a+n+1);
	int i,sum = 0;
	for(i = 1; i <= n; i++){
		int mmin = b[1];
		int xb = 1;
		for(int j = 1; j <= m; j++){
			if(mmin > b[j]){
				xb = j;
				mmin = b[j];
			}
		}
		//cout << xb << " " << mmin << endl;
		sum += mmin;
		b[xb] += a[i];
	}
	printf("%d",sum);
    return 0;	
} 

排队打水问题

题目链接:https://www.dotcpp.com/oj/problem1527.html
贪心
思路:
和上一题一样,只不过这里是所有人的等待时间加上所有人打水的时间。

#include <bits/stdc++.h>
#include <algorithm>
#include <cmath>
#define mod 1000000007
#define ll long long

using namespace std;

int a[1005],b[1005],c[1005];
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i = 1; i <= n; i++) 
	    scanf("%d",&a[i]);
	sort(a+1,a+n+1);
	int i,sum = 0;
	for(i = 1; i <= n; i++){
		sum += a[i];
		int mmin = b[1];
		int xb = 1;
		for(int j = 1; j <= m; j++){
			if(mmin > b[j]){
				xb = j;
				mmin = b[j];
			}
		}
		//cout << xb << " " << mmin << endl;
		sum += mmin;
		b[xb] += a[i];
	}
	printf("%d",sum);
    return 0;	
} 

摆花

题目链接:https://www.dotcpp.com/oj/problem1529.html
1)考虑状态:dp[i][j] 表示用前i种花摆j盆的方案数
2)状态转移:选第i种花并选k种 则有dp[i-1][j-k]种,不选第i种花,则有dp[i-1][j]种,两者和就是dp[i][j]的答案
3)初始化,当摆0盆花时,都是1种方案,就是不摆
小技巧:
一般这种动态规划可以从题目要求的答案出发去找状态

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
const int mod = 1e6+7;
using namespace std;

int dp[105][105];
int a[105];
//dp[i][j]:表示用前i种花摆j盆的方案数 
int main() 
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i = 1; i <= n; i++){
		scanf("%d",&a[i]);
	}
	for(int i = 0; i <= n; i++){
		dp[i][0] = 1;
	}
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			dp[i][j] = dp[i - 1][j];//不选第i种花 
			for(int k = 1; k <= a[i] && k <= j; k++){
				dp[i][j] = (dp[i - 1][j - k] + dp[i][j]) % mod;//选第i种花,并选k盆 
			}
		}
	}
	printf("%d\n",dp[n][m] % mod);
	return 0;
}

18年蓝桥杯省赛c/c++B组

日志统计

题目链接:https://www.dotcpp.com/oj/problem2279.html
思路:以id为下标,用vector保存这个id获得赞的时刻,在查询之前先对时刻排序,然后利用尺取法查询是否在d时间内获得赞数大于等k。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cstring>
#include <set>
#include <map>
#define ll long long
const int mod = 1e9+7;

using namespace std;

vector<int>a[100005]; 
int main()
{
    int n,d,k,ts,td,id = 0;
    scanf("%d%d%d",&n,&d,&k);
    for(int i = 1; i <= n; i++){
    	scanf("%d%d",&ts,&td);
    	a[td].push_back(ts);
    	id = max(td,id); 
    	
	}
	for(int i = 0; i <= id; i++){
		int l = a[i].size();
		if(l < k) continue;
		sort(a[i].begin(),a[i].end());
		int le = 0,ri = 0,flag = 0,t = 0;
		while(le <= ri && ri < l){
			t++;
			if(t >= k){
				if(a[i][ri] - a[i][le] < d){
					flag = 1;
					printf("%d\n",i);
					break;
				}
				else le++,t--;
			}
			ri++;
		}
	}
	return 0;
}

乘积尾零

如下的10行数据,每行有10个整数,请你求出它们的乘积的末尾有多少个零?
5650 4542 3554 473 946 4114 3871 9073 90 4329
2758 7949 6113 5659 5245 7432 3051 4434 6704 3594
9937 1173 6866 3397 4759 7557 3070 2287 1453 9899
1486 5722 3135 1170 4014 5510 5120 729 2880 9019
2049 698 4582 4346 4427 646 9742 7340 1230 7683
5693 7015 6887 7381 4172 4341 2909 2027 7355 5649
6701 6645 1671 5978 2704 9926 295 3125 3878 6785
2066 4247 4800 1578 6652 4616 1113 6205 3264 2915
3966 5291 2904 1285 2193 1428 2265 8730 9436 7074
689 5510 8243 6114 337 4096 8199 7313 3685 211
思路一: 任何一个数中有零都是直接或间接通过2*5得来的,所以我们只需要判断每个数的可以分解出多少个2或5,然后取两者中小的那个就是答案。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cstring>
#include <set>
#include <map>
#define ll long long
const int mod = 1e9+7;
const ll ds = 1e15+7;
using namespace std;

int main()
{
	int x,cnt5 = 0,cnt2 = 0;
	for(int i = 1; i <= 100; i++){
		cin >> x;
		int k = x;
		while(x % 2 == 0){
			cnt2++;
			x /= 2;
		}
		while(k % 5 == 0){
			cnt5++;
			k /= 5;
		}
	}
	cout << min(cnt2,cnt5);
	return 0;
}
//答案为31。

明码

汉字的字形存在于字库中,即便在今天,16点阵的字库也仍然使用广泛。
16点阵的字库把每个汉字看成是16x16个像素信息。并把这些信息记录在字节中。
一个字节可以存储8位信息,用32个字节就可以存一个汉字的字形了。
把每个字节转为2进制表示,1表示墨迹,0表示底色。每行2个字节,
一共16行,布局是:
第1字节,第2字节
第3字节,第4字节
….
第31字节, 第32字节
这道题目是给你一段多个汉字组成的信息,每个汉字用32个字节表示,这里给出了字节作为有符号整数的值。
题目的要求隐藏在这些信息中。你的任务是复原这些汉字的字形,从中看出题目的要求,并根据要求填写答案。
这段信息是(一共10个汉字):
4 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 0
16 64 16 64 34 68 127 126 66 -124 67 4 66 4 66 -124 126 100 66 36 66 4 66 4 66 4 126 4 66 40 0 16
4 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 0
0 -128 64 -128 48 -128 17 8 1 -4 2 8 8 80 16 64 32 64 -32 64 32 -96 32 -96 33 16 34 8 36 14 40 4
4 0 3 0 1 0 0 4 -1 -2 4 0 4 16 7 -8 4 16 4 16 4 16 8 16 8 16 16 16 32 -96 64 64
16 64 20 72 62 -4 73 32 5 16 1 0 63 -8 1 0 -1 -2 0 64 0 80 63 -8 8 64 4 64 1 64 0 -128
0 16 63 -8 1 0 1 0 1 0 1 4 -1 -2 1 0 1 0 1 0 1 0 1 0 1 0 1 0 5 0 2 0
2 0 2 0 7 -16 8 32 24 64 37 -128 2 -128 12 -128 113 -4 2 8 12 16 18 32 33 -64 1 0 14 0 112 0
1 0 1 0 1 0 9 32 9 16 17 12 17 4 33 16 65 16 1 32 1 64 0 -128 1 0 2 0 12 0 112 0
0 0 0 0 7 -16 24 24 48 12 56 12 0 56 0 -32 0 -64 0 -128 0 0 0 0 1 -128 3 -64 1 -128 0 0

注意:需要提交的是一个整数,不要填写任何多余内容。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cstring>
#include <set>
#include <map>
#define ll long long
const int mod = 1e9+7;

using namespace std;

void print(int x)
{
	if(x < 0){
		x = -x;
		x = ~x;
		x += 1;
		//x += 256;
	}
	for(int i = 7; ~i ; i--){
		if(x & (1 << i)) printf("*");
		else printf(" ");
	}
}

int main()
{
    int n,m;
    int a[11][35]; 
    n = 10,m = 32;
    for(int i = 1; i <= 10; i++){
    	for(int j = 1; j <= 32; j++){
    		int x;
    		cin >> a[i][j];
		}
	}
	for(int i = 1; i <= 10; i++){
		for(int j = 1;  j <= 32; j++){
			print(a[i][j]);
			if(j % 2 == 0) printf("\n");
		}
	}
//	ll ans = 9;
//	for(int i = 1; i < 9; i++){
//		ans *= 9;
//	}
    ll ans = pow(9,9);
	printf("%lld",ans);
	return 0;
}
//输出问题为九的九次方等于多少?
//答案:387420489
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值