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=knCi−1k−1∗arr[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;
}
}