207 快快变大
区间DP
本题显然不是使用简单的贪心思想规定排序的规则就可以解决的
确定一下状态转移方程dp[1] [n]=dp[1] [k]+dp[k+1] [n]+(a1k*ak+1n)
之后使用前缀积去存储答案
#include<bits/stdc++.h>
using namespace std;
long long num[305][305];
long long dp[305][305];
#define mode 1000003
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)cin >> num[i][i];
//计算前缀和的方式
for (int i = 1; i <= n; i++)
{
for (int j = i + 1; j <= n; j++)
{
num[i][j] = num[j][j];
num[i][j] = (num[i][j] * num[i][j - 1]) % mode;
}
}
for (int len = 2; len <= n; len++)
{
for (int l = 1, r = l + len - 1; r <= n; l++,r++)//二重循环是在根据区间长度遍历所有的区间
{
for (int k = l; k < r; k++)//三重循环则是在遍历每一个区间里的子区间
{
dp[l][r] = max(dp[l][r], dp[l][k] + dp[k + 1][r] + (num[l][k] - num[k + 1][r]) * (num[l][k] - num[k + 1][r]));
}
}
}
cout << dp[1][n] << endl;
return 0;
}
501 RSA
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
//原题链接:http://oj.daimayuan.top/course/11/problem/617
//本题的难点在于判断是否是partial credit
//还是采用在饿饿 饭饭2中使用过的思想 将一个数字分解成许多个质数的乘积
//如果因子出现的次数超过二 那么就不是partial credit
long long a, b;
map<int, int>Map;
int main()
{
cin >> a >> b;
if (a == b)
{
printf("no credit");
return 0;
}
for (int i = 2; i <= (int)sqrt(a); i++)
{
if (a % i == 0)
{
Map[i]++;
Map[a / i]++;
}
}
for (int i = 2; i <= (int)sqrt(b); i++)
{
if (b % i == 0)
{
Map[i]++;
Map[b / i]++;
}
}
if (Map.empty())
{
printf("full credit");
return 0;
}
for (auto i = Map.begin(); i != Map.end(); i++)
{
int x = sqrt(i->first);
if (i->second >= 2||x*x==i->first)
{
printf("no credit");
return 0;
}
}
printf("partial credit");
return 0;
}
502 数组操作
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
//原题链接:http://oj.daimayuan.top/course/11/problem/610
//从后面的数字向前面的数字赋值 即使全部的数字都与最后一个数字相同
int t;
int main()
{
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
vector<int >V(n);
for (int i = n - 1; i >= 0; i--)
{
cin >> V[i];
}
int num = V[0], ans = 0, now = 1;
while (now < n)
{
if (V[now] == num)
{
now++;
}
else
{
now *= 2;
ans++;
}
}
cout << ans << '\n';
}
return 0;
}
503 A-B数对
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
//原题链接:http://oj.daimayuan.top/course/11/problem/616
//由于c是正整数 所以基本思路就是从大到小遍历
//由于题目说明 不同位置 相同数字的数算不同的数字 要重复计算
//那么 若使用基本的两层遍历
//题目2e5的数据 O(N^2)的时间复杂度肯定会爆
//那么考虑优化
//1、二分是必然的
//2、无法用set数组去重 因为数字重复也算多个数字
//由此 这里思考 用Map去存储 因为一个数字的位置和自己的值想必是无关的
//如果这个a-b=c合法 那么我们只需要用|a|*|b|即ab的个数积即可
//ans += i->second * j->second;
//
//此外用到了lower_bound() 能调用的绝不自己写二分
int n, c;
int ans;
map<int, int>Map;
int main()
{
scanf("%d%d", &n, &c);
for (int i = 0; i < n; i++)
{
int temp;
scanf("%d", &temp);
if (Map.count(temp))
Map[temp]++;
else
Map[temp] = 1;
}
for (auto i=Map.rbegin(); i!=Map.rend() ; i++)
{
//lower_bound(begin, end, num)
auto j = Map.lower_bound(i->first-c);
for (j;j!=Map.end(); j++)
{
if (i->first - j->first == c)
{
ans += i->second * j->second;
}
else
break;
}
}
printf("%d", ans);
return 0;
}
504 数位计算
对于本题数据 直接使用循环去计算数位显然是我们不能接受的 但是一个数字 对于所有低于本位的情况都是固定的 我们可以提前处理好这些固定的数字 之后对于本位数字 我们做一个简单的处理即可
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int wei(ll x)
{
int cnt = 0;
while (x > 0)
{
x /= 10;
cnt++;
}
return cnt;
}
ll n;
ll a, b;//首项+尾项,项数
ll ans;
ll mode = 998244353;
ll p = 10;
int main()
{
cin >> n;
while (1)
{
if (n > p - 1)
{
a = (p - p / 10 + 1) % mode;
b = (p - p / 10) % mode;
ans = (ans + (a * b / 2) % mode) % mode;
}
else
{
a = (1 + n - p / 10 + 1) % mode;
b = (n - p / 10 + 1) % mode;
ans = (ans + (a * b / 2) % mode) % mode;
break;
}
p *= 10;
}
cout << ans << endl;
return 0;
}
505 新国王游戏
这道题和之前做过的国王游戏具体没有什么差别 还是找到需要遵循贪心规则即可 而且由于出现了取模运算 并不需要使用高精度就可以完成
同时 对于每一个人 除了自己右手上的数字是浮动的 其前的所有人 左手数字的加和都没有区别 所以可以使用前缀和的思想来降低复杂度
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1000000007;
const ll maxn=1e6+5;
typedef struct
{
ll a,b;
}u;
u ar[maxn];
bool cmp(u x,u y)
{
return x.b*(y.a-1)>y.b*(x.a-1);
}
int main(void)
{
ll n,i,ans;
scanf("%lld",&n);
for(i=0;i<n;i++)
scanf("%lld%lld",&ar[i].a,&ar[i].b);
sort(ar,ar+n+1,cmp);
ans=0;
for(i=1;i<=n;i++)
{
ans=(ans*ar[i].a+ar[i].b)%mod;
}
printf("%lld\n",ans);
return 0;
}
506 完美数
这里主要是使用了快速幂求乘法逆元的操作 这里直接介绍一下二进制求快速幂
实际上就是用二进制数去表示任意一个数的任意次幂
就是说 如同4可以表示为0100一样 任意一个数字 由二进制表示以后 选择乘或不乘就可以组合为想要的幂次
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mode 1000000007
#define N 1000005
ll qpow(ll a, ll n)//快速幂模板
{
ll ans = 1;
while (n)
{
if (n & 1)
{
ans = ans*a%mode;
}
a = a * a % mode;
n >>= 1;
}
return ans;
}
ll a, b, m;
ll f[N], nif[N];//存储阶乘与阶乘逆元
ll C(ll a, ll b)
{
return (f[a] * nif[b] % mode * nif[a - b] % mode)%mode;//计算组合数
}
int main()
{
cin >> a >> b >> m;
ll ans=0;
//预处理,我们要先计算出数字模乘的阶乘,然后算出他们的逆元
f[0] = 1;
nif[0] = 1;
for (ll i = 1; i < N; i++)
{
f[i] = i * f[i - 1] % mode;
}
nif[N-1] = qpow(f[N-1], mode - 2);//n-1的逆元就是n的逆元乘以n
for (ll i = N-2; i >= 1; i--)
{
nif[i] = nif[i + 1] * (i + 1) % mode;
}
//一切处理完毕,直接计算即可。
for (ll i = 0; i <= m; i++)
{
ll cnt = i * a + (m - i) * b;
bool flag = 0;
while (cnt)
{
if (cnt % 10 != a && cnt % 10 != b)
{
flag = 1;
break;
}
cnt /= 10;
}
if (flag == 1)continue;
ans = (ans + C(m, i))%mode;
}
cout << ans%mode << endl;
return 0;
}
601 BFS练习
由于给定的数字a是不变的 只是需要从a变到给定的许多个b所需要的步数 那么就不需要每次都对不同的b进行一次预处理
我们可以直接统计从给定的a到任意值需要的步骤
最后根据不同的b
直接输出答案就好
#include<bits/stdc++.h>
using namespace std;
int a, q, b;
int vis[100000+5];
queue<int>Q;
void bfs(int a)
{
vis[a] = 0;
Q.push(a);
while (!Q.empty())
{
int temp = Q.front();
Q.pop();
if (temp + 1 >= 1 && temp + 1 <= 100005 && vis[temp + 1] == -1)
{
Q.push(temp + 1);
vis[temp + 1] = vis[temp] + 1;
}
if (temp - 1 >= 1 && temp - 1 < 100005 && vis[temp - 1] == -1)
{
Q.push(temp - 1);
vis[temp - 1] = vis[temp] + 1;
}
if (temp * 2 >= 1 && temp * 2 < 100005 && vis[temp * 2] == -1)
{
Q.push(temp * 2);
vis[temp * 2] = vis[temp] + 1;
}
if (temp * 3 >= 1 && temp * 3 < 100005 && vis[temp * 3] == -1)
{
Q.push(temp * 3);
vis[temp * 3] = vis[temp] + 1;
}
}
}
int main()
{
memset(vis, -1, sizeof(vis));
cin >> a >> q;
bfs(a);
while (q--)
{
cin >> b;
cout << vis[b] << " ";
}
return 0;
}