第一题 数组操作
题面http://oj.daimayuan.top/course/11/problem/610
出题人的表达能力有待加强,大意就是把后面一个区间中的所有数赋给前面的一个区间,所以只能把所有数变成最后一个数,因为只能后赋前,所以我们就从后往前遍历,相同跳过,不同num++,并且i-=n-2-i,写的时候被我for里面的i–给坑了。。。
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e6 + 10;
int ori[maxn];
int main() {
int t;
scanf("%d", &t);
while (t--)
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &ori[i]);
}
int num = 0;
int last = ori[n - 1];
int i;
for (i = n - 2; i >= 0; i--) {
if (ori[i] == last)continue;
num++;
i -= n -2 - i;
}
//if (i != -1) {
// num++;
//}
printf("%d\n", num);
}
}
第二题 A-B 数对
题面http://oj.daimayuan.top/course/11/problem/616
用map存每个数字出现的次数,之后num+=当前数字出现的个数*当前数字+c出现的个数。
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e6 + 10;
map<int, int> num_shuzi;
int main() {
int n,c;
scanf("%d%d", &n,&c);
for (int i = 0; i < n; i++) {
int temp;
scanf("%d", &temp);
num_shuzi[temp]++;
}
map<int, int>::iterator it;
int num = 0;
for (it = num_shuzi.begin(); it != num_shuzi.end(); it++) {
if (it->second == 0)continue;
num += it->second * num_shuzi[it->first + c];
}
printf("%d", num);
}
第三题 数位计算
题面http://oj.daimayuan.top/course/11/problem/666
大概,就是求和,10到99,100到999这样,但1到9要单独讨论,
#define _CRT_SECURE_NO_WARNINGS
#define ll long long
#include<bits/stdc++.h>
using namespace std;
const int mod = 998244353;
ll n;
int main() {
scanf("%lld", &n);
ll temp = n;
int num = 0;
ll sum = 0;
ll s0 = 1, s9 = 9;
while (temp > 9)
{
num++;
temp /= 10;
if (num == 1) {
sum += (s9 - s0 + 1) * (1 + 9) / 2;
}
else {
sum += ((s9 - s0 + 1) * (2 + s9 - s0) / 2)% mod;
}
//sum += (s9 - s0) + 1;
s9 = (s9 * 10 + 9)%mod;
s0 *= 10;
s0% mod;
}
sum += ((n - s0 + 1) * (1 + (num == 0 ? n : n - s0 + 1)) / 2)% mod;
printf("%lld", sum%mod);
}
第四题 新国王游戏
题面:http://oj.daimayuan.top/course/11/problem/672
最开始的想法是,左手上的所有数都要累乘,之后再分别乘右手的数,如此,可知,把左手越大的数越往后面放,可以让这个大数对和的贡献更大。但发现一个反例,
2
8 1
10 100
明显
10 100
8 1
更大
根据这个特例,猜测cmp函数应改成
bool cmp(int a, int b) {
return !(ori[a][1]*ori[b][0]+ori[b][1]>ori[b][1]*ori[a][0]+ori[a][1]);
}
后续查到这个方法叫交换法?大致原理就是
ai代表第i个人
a1,a2,a3,ai,ai+1,an
对于ai和ai+1,若把ai+1与ai交换,前面的大臣的获得不会变,后面的也不会变,因为只是乘,所以对于所有的ai+1和ai,若ai+1放前面答案会更大,就要交换,从整体来看,所有满足交换后更大的两项都要交换,类似于冒泡排序,既然是排序,可以直接用sort。
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
using namespace std;
const int maxn = 1e6 + 10;
const int MOD = 1000000007;
long long ori[maxn][2];
int orinew[maxn];
//记录顺序下标
bool cmp(int a, int b) {
return ori[a][1]*ori[b][0]+ori[b][1]>ori[b][1]*ori[a][0]+ori[a][1];
}
int main() {
//ios::sync_with_stdio(false);
//cin.tie(0);
//cout.tie(0);
int n;
cin >> n;
for (int i = 0; i < n; i++) {
scanf("%d%d", &ori[i][0], &ori[i][1]);
orinew[i] = i;
}
sort(orinew, orinew + n, cmp);
long long sum = 0;
long long suml = 1;
for (int i = n-1; i >= 0; i--) {
sum = (sum+suml * ori[orinew[i]][1])%MOD;
suml = (suml*ori[orinew[i]][0])%MOD;
}
//sum = (sum+ori[orinew[n - 1]][1])%MOD;
printf("%lld",sum);
// ll sum = 1;
// ll res1 = ori[orinew[0]][1];
// for (int i = 0; i < n; i++)
// {
// if (i > 0)res1 = (res1 + (sum * ori[orinew[i]][1]) % MOD) % MOD;
// sum = (sum * ori[orinew[i]][0]) % MOD;
// }
// printf("%lld",res1);
// return 0;
}
第五题 完美数
题面:http://oj.daimayuan.top/course/11/problem/669
先找出几个a,几个b的情况符合题意,再组合数插空算num,但是,这个鬼取模不能用先乘后除的方法取模算,只能用c m/n=c m/n-1+c m-1/n-1,递归取模来算,
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
#define ll long long
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
using namespace std;
ll a, b, m;
//ll zuhe(ll i) {
// ll sum = 1, up = min(i, m - i), down = m - up+1;
// for (ll j = 1; j <= up;j++) {
// sum = (sum * (down-up+j)/j) % mod;
// }
// //for (ll j = up; j >= 1; j--) {
// // sum /= j;
// //}
// return sum;
//}
map<ll, map<ll, ll>>res;
ll zuhe(ll down,ll up) {
if (up == 0 || up == down) return 1;
if (res[down][up] != 0)return res[down][up];
return res[down][up] = (zuhe(down - 1, up) + zuhe(down, up - 1))%mod;
}
int main() {
scanf("%lld%lld%lld", &a, &b, &m);
if (a > b)swap(a, b);
ll min1 = a * m;
ll num = 0;
ll temp = min1;
while (temp > 0)
{
if (temp % 10 != a && temp % 10 != b) {
num--;
break;
}
temp /= 10;
}
num++;
//全为a
for (ll i = 1; i <= m-1; i++) {
//有i个b,
min1 = min1 - a + b;
temp = min1;
bool no = 0;
while (temp>0)
{
if (temp % 10 != a && temp % 10 != b) {
no=1;
break;
}
temp /= 10;
}
if (!no) {
ll up = min(i, m - i);
num = (num+zuhe(m-up+1,up))%mod;
}
}
min1 = b * m;
temp = min1;
while (temp > 0)
{
if (temp % 10 != a && temp % 10 != b) {
num--;
break;
}
temp /= 10;
}
num++;
printf("%lld", num);
}
第六题 Lusir的游戏
题面http://oj.daimayuan.top/course/11/problem/674
初始能量取值范围在[最小高度,最大高度]
在模拟一个能量能不能选的时候,若半途这个能量已近累加到比最大还大了,就不用算后面的了,一定可以。
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
long long ori[maxn];
int n;
int main() {
scanf("%d", &n);
long long minori = 2e5, maxori = -2;
for (int i = 1; i <= n; i++) {
scanf("%d", &ori[i]);
minori = min(minori, ori[i]);
maxori = max(maxori, ori[i]);
}
for (int i = minori; i <= maxori; i++) {
long long temp = i;
bool yes = 1;
for (int j = 1; j < n; j++) {
temp += temp - ori[j];
if (temp > maxori) {
break;
}
if (temp < 0) {
yes = 0;
break;
}
}
if (yes) {
cout << i;
return 0;
}
}
cout << maxori;
}
第七题 BFS练习
题面http://oj.daimayuan.top/course/11/problem/147
题读错了我去,这题应该是在由a构成的树里面找bi,而我傻啦吧唧的写成了每次都从头开始找bi,应该是一次找完所有bi,每个bi的步骤等于它所在的deep,我还傻乎乎的写了个A*来优化。。。。。
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int a, q, n;
//int ori[maxn];
//int minlen = 0x7fffffff;
struct node
{
int num;
int coast;
friend bool operator <(node a, node b) {
return a.coast > b.coast;
}
};
map<int, int> again;
map<int, int> len;
void bfs(int n) {
priority_queue<node> dui;
node ori;
ori.coast = abs(n - a);
ori.num = a;
dui.push(ori);
again[a] = 1;
//int len = 0;
while (!dui.empty()) {
node duitop = dui.top();
dui.pop();
if (duitop.num < 0)continue;
if (duitop.num == n) {
printf("%d ", len[n]);
break;
}
//again[duitop] = 1;
if (!again[duitop.num + 1]) {
node temp = duitop;
temp.num++;
temp.coast = abs(n - temp.num);
dui.push(temp);
len[duitop.num + 1] = len[duitop.num] + 1;
again[duitop.num + 1] = 1;
}
if (!again[duitop.num - 1]) {
node temp = duitop;
temp.num--;
temp.coast = abs(n - temp.num);
dui.push(temp);
len[duitop.num - 1] = len[duitop.num] + 1;
again[duitop.num - 1] = 1;
}
if (!again[duitop.num * 2]) {
node temp = duitop;
temp.num*=2;
temp.coast = abs(n - temp.num);
dui.push(temp);
len[duitop.num * 2] = len[duitop.num] + 1;
again[duitop.num * 2] = 1;
}
if (!again[duitop.num * 3]) {
node temp = duitop;
temp.num*=3;
temp.coast = abs(n - temp.num);
dui.push(temp);
len[duitop.num * 3] = len[duitop.num] + 1;
again[duitop.num * 3] = 1;
}
}
}
int main() {
scanf("%d%d", &a, &q);
while (q--)
{
scanf("%d", &n);
again.clear();
len.clear();
//minlen = 0x7fffffff;
bfs(n);
//cout << minlen<<" ";
}
}
第八题 01序列2
题面http://oj.daimayuan.top/course/11/problem/700
看取模猜是dp递推出来的,然后确实
dp[i]代表长为i,k个0的种类
dp[i-1]中的所有类型,后面在填1或0,得到dp[i-1]*2种,这之中加0的肯定可行,而另一半要减,末尾是1的,10,100的,具体0取决于k,一共要减k次,每次减dp[i-k-2-j]个
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e6 + 10;
const ll mod = 1e9 + 7;
ll dp[maxn];
int main() {
dp[0] = 1;
ll n, k;
scanf("%lld%lld", &n, &k);
for (int i = 1; i <= k; i++) {
dp[i] = i + 1;
}
for (ll i = k+1; i <= n; i++) {
ll temp = dp[i-1];
for (int j = 0; j < k; j++) {
temp = (temp-dp[i - k - 2 - j>0?i-k-2-j:0]);
if (temp < 0)cout << temp << endl;
}
dp[i] = ( temp+ dp[i - 1])%mod;
}
cout << dp[n]%mod;
}