人工智能实验室8月份题单

1.zzulioj1828:贪心的小猫咪

贪心题,观察即可发现,找到给出的数中第一个比前面一个数小的数删去即可,如果没有则删除最后一个数。字符串长度为1时,删去后变成0。

#include<bits/stdc++.h>
using namespace std;
int main(){
	string str;
	while(cin >> str){
		int ansi=-1;
		for(int i = 1; i<str.size(); i++){
			if(str[i] < str[i-1]){
				ansi = i-1;break;
			}
		}
		if(ansi == -1) ansi = str.size()-1;
		if(str.size() == 1) cout << "0";
		for(int i = 0; i<str.size(); i++){
			if(i != ansi) cout << str[i];
		}cout << endl;
	}
}

2.zzulioj1667:跳楼梯

简单dp,数据很小递归也行,dp可以用前缀和优化掉一层循环~如下。

#include<bits/stdc++.h>
using namespace std; 
typedef long long ll;
ll dp[100];
int main(){
	int m, n;
	while(cin >> m >> n){
		memset(dp,0,sizeof(dp));
		dp[0] = 1;
		ll f = 1;
		for(int i = 1; i<=m; i++){
			dp[i] = f;
			f += dp[i];
			if(i-n >= 0) f -= dp[i-n];
		}
		cout << dp[m] << "\n";
	}
}

3. zzulioj2214: 小明防AK

将数组用两种方法排序后,跟原来的数组比较求出最大值即可。

#include<bits/stdc++.h>
using namespace std;
int arr[1010];
int arr2[1010], arr3[1010];

bool cmp(int a, int b){
	return a>b;
}
int main(){
	int n;
	while(cin >> n){
		for(int i = 0; i<n; i++){
			cin >>arr[i];
			arr2[i] = arr3[i]= arr[i];
		}
		sort(arr,arr+n);
		sort(arr2, arr2+n, cmp);
		int ans1 = 0, ans2 = 0;
		for(int i = 0; i<n; i++){
			if(arr[i] == arr3[i]) ans1++;
			if(arr2[i] == arr3[i]) ans2++;
		}
		cout << max(ans1, ans2)<< endl;
	}
}

4.zzulioj2609: 初识堆栈

模拟栈操作即可,或者直接使用stack数据结构。数据貌似有坑?好像会出现为空。

#include<bits/stdc++.h>
using namespace std;

int main(){
	int n, m;
	string str;
	cin >> n >> m;
	while(n--){
		int f = 0, f2 = 1;
		cin >>str;
		for(int i = 0; i<str.size(); i++){
			if(str[i] == 'S') f++;
			else f--;
			if(f<0||f>m) {
				f2 = 0; break;
			}
		}
		if(f2 && f==0) cout << "YES\n";
		else cout << "NO\n";
	}
}

2635: F

一个贪心问题。
先将两个数组排序(此题解为从小到大排)。
两个数组相加,求第p大的数字最大是多少, 不用管两个数组的前(n-p)项 (很容易证明,如果加上两个数组的前n-p项的数字一定会使最后的值变小) 。所以只需要看两个数组中第(n-p)到第n项的数。让第p大的数最大,则需要让这p个数的整体值每一项最小~(不明白的话好好缕缕)所以用一个数组的第(n-p)项与另一个数组的第n项相加, 第(n-p+1)项与(n-1)项相加… 求出这些数中的最小值就是答案。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 1e5+10;
ll arr1[maxn], arr2[maxn];
int main(){
	int n, p;
	cin >> n >> p;
	for(int i = 0; i<n; i++) cin >>arr1[i];
	for(int i = 0; i<n; i++) cin >>arr2[i];
	sort(arr1,arr1+n);
	sort(arr2,arr2+n);
	ll ans = 1e15;
	for(int i = n-p, j = n-1; i < n; i++, j--){
		ans = min(arr1[i]+arr2[j], ans);
	}
	cout << ans;
	
}

2637: H

画个图,很容易用余弦定理求出n边形的边长~

#include<bits/stdc++.h>
using namespace std;

map<int, int> mp;
int main() {
	double n, r, pi = 3.14;
	while(cin >> n >> r)
		printf("%.2lf\n", n * sqrt((r*r)*2-2*(r*r)*cos(2*pi/n)));
}

1802: SC借水

直接算~

#include<bits/stdc++.h>
using namespace std;
int main(){
	int t, v, k, s, e;
	cin >> t;
	while(t--){
		cin >> v >> k >> s >> e;
		cout << min(v,e/k-s/k+(s%k==0)) << endl; 
	}
}

1542: 天天的钢琴

看起来难,其实很简单,就是求组合数。
看样例
5 3
2 4 2 3 4
排个序就是 2 2 3 4 4
同时按3个键情况下
想要出现2声音,一定需要先选一个2, 然后选2个 小于等于2 的数,2前面的数不能符合条件。
出现3声音,需要先选一个3, 然后选2个 小于等于3 的数。前面有2个符合条件的数,方案数为C(2,2)。
出现4声音,需要先选一个4, 然后选2个小于等于4 的数。
选第一个4,前面有3个符合条件的数,方案数为C(3,2),
选第二个4,前面有4个符合条件的数,方案数为C(4,2)。
推广到所有答案就是 ∑ i = k n C i − 1 k − 1 ∗ a r r [ i ] \sum_{i=k}^{n} C_{i-1}^{k-1} *arr[i] i=knCi1k1arr[i]
注意用值很大,要用long long。求组合数的次数比较多,需要先预处理一下,不然会超时。

#include<bits/stdc++.h>
#define eps 1e-9
#define pb push_back
#define fi first
#define se second
#define endl '\n'
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define db1(x) cout << #x << " = " << x << endl
#define db2(x, y) cout << #x << " = " << x << " " << #y << " = " << y << endl
#define gg cout << "---------------------\n"
using namespace std;

typedef long long ll;
typedef long double llb;
const ll INF = 0x3f3f3f3f3f3f; 
const int maxn = 1e5+10;
const int mod = 1e9+7;
const ll N = 1e18;

ll arr[maxn];

ll MOD(ll a, ll m) {  // 取余
    a %= m;
    return a >= 0 ? a : a + m;
}
// m为质数时, a的逆元为 a^m-2。
ll inverse(ll a, ll m) {  // 求a mod m时的逆元
    a = MOD(a, m);
    if (a <= 1) return a;
    return MOD((1 - 1ll*inverse(m, a) * m) / a, m) %mod;
}

int fac[maxn];
int facinv[maxn];
void init() {
    fac[0] = 1;
    for (int i = 1; i < maxn; ++i)
        fac[i] = (1ll * i * (fac[i - 1]))% mod;
    facinv[maxn - 1] = 1l*inverse(fac[maxn - 1], mod) %mod;
    for (int i = maxn - 2; i >= 0; --i){
        facinv[i] = 1ll * facinv[i + 1] * (i + 1) % mod;
    }
}
//求组合数 c[n,m],调用之前需要先调用init().
ll combi(int n, int m) {
    if (n < 0 || m < 0 || n < m)return 0;
    return 1ll * fac[n] *1ll* facinv[m] % mod * facinv[n - m] % mod;
}

int main(){
	io; init();
	ll n, m, ans = 0;
	cin >> n >> m;
	for(int i = 1; i<=n; i++)cin >> arr[i];
	sort(arr+1,arr+n+1);
	for(int i = m; i<=n; i++){
		ans = (ans+combi(i-1,m-1)*arr[i]) % mod;
	}
	cout << ans;
}

2138: 序列归并

读完题可以很容易发现,其实就是分别求这两个数组的最大子序和(不了解可以百度)。也可以用dp求。

#include<bits/stdc++.h>
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define endl '\n'
using namespace std; 
typedef long long ll;
const int maxn = 1e5+10;
const ll inf = -1e9-10;
int main(){
	io;
	int t, n, m;
	cin >> t;
	while(t--){
		ll a, mx1=inf, mx2=inf, f1=inf, f2=inf;
		cin >> n >> m;
		for(int i = 0; i<n; i++){
			cin >> a;
			f1 = max(a, a+f1);
			mx1 = max(f1, mx1);
		}
		for(int i = 0; i<m; i++){
			cin >> a;
			f2 = max(a, a+f2);
			mx2 = max(f2, mx2);
		}
		cout << mx1 + mx2 << endl;		
	}
	return 0;
}

1555: 神殿

数据范围2*1e9,不能暴力。求[l, r]中所有数的二进制表示里,1的个数最多的一个数,且是最小的。
可以用位运算从小到大 将l的每一位变成1,直到l的值大于r。最大的值就是l的前一次变化的值。
比如
l = 5 (00000101)
r= 25(00011001)
第一次变为 5 (00000101)
第二次变为 7 (00000111)
第三次变为 7 (00000111)
第四次变为 15 (00001111)
第五次变为 31 (00011111)
答案就是15。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
int main() {
	ll l, r, c = 0;
	cin >> l >> r;
	while(1){
		ll t = l|(1ll<<c);
		if(t > r) break;
		else l = t;		
		c++;
	}
	cout << l;
}

1873: This offer

数据范围很小,直接暴力,直接用map统计每一次能获得的值,顺便还能去重。直接用vector插入,再去重也行。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 1e5+10;

int arr[100];
int main(){
	int n;
	while(cin >> n){
		map<int,int>mp, mp1;
		for(int i = 1; i<=n; i++) cin >> arr[i];
		mp[arr[1]] = 1;
		for(int i = 2; i<=n; i++){
			mp1.clear();
			for(auto j = mp.begin(); j!=mp.end(); j++){
				int t = j->fi;
				mp1[t+arr[i]] = 1;
				mp1[t-arr[i]] = 1;
			}
			mp = mp1;
		}
		cout << mp.size() << endl;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值