校门外的树
主要是差分的思想,当然数据量较小暴力也能做,用一个数组a[],假设l-r区间的树被移除,则a[l]--,a[(r+1)++],然后对a求前缀和,若其为0,则该位置的树未被移除
代码:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
using namespace std;
int L[100007];
int m;
int main()
{
int len;
cin >> len >> m;
for (int i = 0; i < m; i++)
{
int l, r;
cin >> l >> r;
L[l]++;
L[r+1]--;
}
int t = 0;
int ans = 0;
for (int i = 0; i <= len; i++)
{
t+=L[i];
if(!t) ans++;
}
cout << ans << endl;
}
序列求和
模运算:
(a + b) % p = (a % p + b % p) % p
(a - b) % p = (a % p - b % p) % p
(a * b) % p = (a % p * b % p) % p
对于除法的模运算,需要用逆元将除法变为乘法
逆元:整数a,b,满足a * b = 1(mod m),那么称b是a的模m乘法逆元
比如:A/B%C我们可以写成A * (1 / B)% C,这样就是AX%C的形式
x即为a模m的乘法逆元
https://www.cnblogs.com/daybreaking/p/9342060.html
求逆元可参考 以上链接
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
ll ksm(ll a, ll b)
{
ll s = 1;
while (b)
{
if (b & 1) s = s * a % mod;
a = a * a % mod;
b >>= 1;
}
return s;
}
int main()
{
ll inv_6 = ksm(6, mod - 2);
ll a;
while (cin >> a)
{
a %= mod;
printf("%lld\n", a * (a + 1) % mod * (a * 2 + 1) % mod * inv_6 % mod);
}
}
子串
暴力枚举就行,注意当进制大于10的时候10为'A',11为'B'.....
代码:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
const int N = 1e5 + 7;
const int Maxx = 2e5 + 7;
int ans;
int n;
string s;
string gets(int wi, int n)
{
string s="";
for (int i = 1; i <= n; i++)
{
string t = "";
int tt = i;
stack<int> ss;
while (tt)
{
ss.push(tt % wi);
tt /= wi;
}
if (tt) ss.push(tt);
while (!ss.empty())
{
int t1 = ss.top();
ss.pop();
if (t1 >= 10) t += (char)(t1 - 10 + 'A');
else t += to_string(t1);
}
s += t;
}
return s;
}
void solve()
{
cin >> n;
cin >> s;
for (int i = 2; i <= 16; i++)
{
if (gets(i, n).find(s) != string::npos) {
cout << "yes\n";
return;
}
}
cout << "no";
}
int main()
{
//cin.tie(0);
//cout.tie(0);
solve();
//cout << gets(16, 15);
}
数学考试
前缀和+尺取法
因为区间为k,所以可以枚举每一个区间,用一个数组maxx[]来存储i以及i以后每一个符号条件区间的和的最大值,然后从前往后枚举即可
因为有负数,记得初始化maxx数组
代码:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
const int N = 2e5 + 7;
int n;
ll ans;
ll t;
ll a[N];//前缀和
ll maxx[N];//保存从i往后选取连续k个数的最大值
ll k;
void solve()
{
ans = -1e18;
cin >> n >> k;
for (int i = 1; i <= n; i++)
{
maxx[i] = -1e18;
cin >> a[i];
a[i] += a[i - 1];
}
for (int i = n - k+1; i >= 1; i--)
{
maxx[i] = max(maxx[i + 1], a[i + k-1] - a[i-1]);
}
for (int i = 1; i+2*k-1 <=n ; i++)
{
ans = max(a[i + k-1] - a[i - 1]+maxx[i + k],ans);
}
cout << ans << endl;
}
int main() {
cin.tie(0);
cout.tie(0);
cin >> t;
while (t--)
{
solve();
}
//solve();
return 0;
}
字符串
尺取法
依次从前往后,枚举左右端点,[l,i]表示区间,用i表示右端点,l表示符合条件的左端点,
若[l,i]不符合,将右端点右移,
若符合,将左端点不断右移直至不符合,在这个过程中更新答案即可
检查区间是否符合可用一个数组arr[]记录区间中a-z的个数,若其中一个为0则不符合
代码:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
const int N = 2e4 + 7;
string s;
int a[26];
int ans;
bool check()//检查是否符合条件
{
for (int i = 0; i < 26; i++)
if (!a[i]) return false;
return true;
}
void solve()
{
cin >> s;
ans = s.size();
int l = 0;
for (int i = 0; i < s.size(); i++)
{
a[s[i] - 'a']++;//更新检查数组
while (check()&&l<i)
{
ans = min(ans, i - l + 1);//更新答案
a[s[l] - 'a']--;//更新检查数组
l++;//符合左端点右移
}
}
cout << ans << endl;
}
int main() {
solve();
return 0;
}
回文数
模拟不同进制间加法
代码:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
typedef long long ll;
using namespace std;
#define x first
#define y second
const int N = 2e5 + 7;
const ll mod = 1e9 + 7;
string s;
int n;
bool check()
{
int i = 0;
int j = s.size() - 1;
while (i<j)
{
if (s[i] != s[j]) return false;
i++;
j--;
}
return true;
}
int getnum(char c)
{
if (isdigit(c)) return c - '0';
else return c - 'A' + 10;
}
char getc(int num)
{
if (num < 10) return num + '0';
else return num - 10 + 'A';
}
void add()
{
int flag = 0;
reverse(s.begin(), s.end());
string tt = s;
reverse(s.begin(), s.end());
int len = s.size();
for (int i = len - 1; i >= 0; i--)
{
int t1 = getnum(s[i]);
int t2 = getnum(tt[i]);
t1 += t2;
if (t1 < n) s[i] = getc(t1);
else {
s[i] = getc(t1 % n);
int t1 = i - 1;
while (t1>=0&&getnum(s[t1])==n-1)
{
s[t1] = '0';
t1--;
}
if (t1 == -1) {
flag = 1;
continue;
}
s[t1] = getc(getnum(s[t1]) + 1);
}
}
if (flag) s = '1' + s;
}
void solve()
{
cin >> n;
cin >> s;
for (int i = 1; i <= 30; i++)
{
add();
//cout << s << endl;
if (check()) {
cout << "STEP=" << i;
return;
}
}
cout << "Impossible!";
}
int main()
{
cin.sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
}
玩具谜题
首先用一个数组按顺序保存其信息即可
也是一个模拟吧,若当前的人朝内,即其状态是0,则向左即减,向右即加
若当前的人朝外,即其状态是1,则向左即加,向右即减
代码:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
const int N = 1e5 + 7;
const int Maxx = 2e5 + 7;
int ans;
int n, q;
struct node {
int z;//状态
string name;
}L[N];
void solve()
{
cin >> n >> q;
for (int i = 0; i < n; i++) cin >> L[i].z >> L[i].name;
int last = 0;
for (int i = 0; i < q; i++)
{
int z, step;
cin >> z >> step;
if (z == 0) {
if (L[last].z == 0) {
last = (last - step+n) % n;
}
else {
last = (last + step) % n;
}
}
else if (z == 1)
{
if (L[last].z == 0) {
last = (last + step) % n;
}
else {
last = (last - step+n) % n;
}
}
}
cout << L[last].name;
}
int main()
{
cin.tie(0);
cout.tie(0);
solve();
}
字符串的展开
模拟,题目可能有点长,但其实应该挺好写的
代码:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
typedef long long ll;
using namespace std;
#define x first
#define y second
const int N = 2e5 + 7;
const ll mod = 1e9 + 7;
int p1, p2, p3;
string s;
void print(char s, char e)
{
int l;//开始位置
int tt;//输出字母还是数字,若是字母,是否大小写
int r;//结束位置
if (isdigit(s)) tt = '0', l = s + 1 - '0', r =e-1-'0';
else {
l = s + 1 - 'a';
r = e - 1 - 'a';
if (p1 == 1) tt = 'a';
else if (p1 == 2) tt = 'A';
}
if (p1 == 3)//输出*
{
for (int i = l; i <= r; i++)
{
for (int j = 0; j < p2; j++)
{
cout << "*";
}
}
return;
}
//逆序输出
if (p3 == 1) {
for (int i = l; i <= r; i++)
{
char c = i + tt;
for (int j = 0; j < p2; j++)
{
cout << c;
}
}
}
//正序输出
else {
for (int i = r; i >= l; i--)
{
char c = i + tt;
for (int j = 0; j < p2; j++)
{
cout << c;
}
}
}
}
void solve()
{
cin >> p1 >> p2 >> p3;
cin >> s;
for (int i = 0; i < s.size(); i++)
{
if (s[i] == '-'&&i&&i!=s.size()-1) {
if (isdigit(s[i - 1]) && isdigit(s[i + 1])) {
if (s[i - 1] < s[i + 1]) {
print(s[i - 1], s[i + 1]);
continue;
}
}
if (islower(s[i - 1]) && islower(s[i + 1])) {
if (s[i - 1] < s[i + 1]) {
print(s[i - 1], s[i + 1]);
continue;
}
}
cout << s[i];
}
else cout << s[i];
}
}
int main()
{
cin.sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
}
减法和除法
思维题,可以看n/2和n-x哪个更小,选择结果小的操作即可
代码:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
const int N = 2e5 + 7;
int n;
int x;
int ans;
void solve()
{
cin >> n >> x;
while (n>0)
{
if (n / 2 < n - x) n /= 2;
else n -= x;
ans++;
}
cout << ans;
}
int main() {
cin.tie(0);
cout.tie(0);
solve();
//solve();
return 0;
}
减法和求余
也是一个思维题,假设给了一个数组,那么最多2次操作即可,第一次对全对2取余,第二次将数组中的1全部减一即可
若数组全为0,则不用操作,即ans=0
当还有以下情况,只用操作一次:
1.数组中除了0全为1
2.当数组中的所有数的最大公约数相同
其他情况即为2
代码:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
const int N = 2e5 + 7;
int n;
int v;
int t0;//0的个数
int t1;//1的个数
int ans = 2;
int gcd(int a, int b)//求最大公约数
{
return b ? gcd(b, a % b) : a;
}
void solve()
{
scanf("%d", &n);
int last;
for (int i = 0; i < n; i++)
{
scanf("%d", &v);
if (!i) last = v;
else last = gcd(v, last);
if (v == 0) t0++;
else if (v == 1) t1++;
}
if(t0==n) ans=0;
else if(t0+t1==n) ans=1;
else if (last != 1) ans = 1;
else ans = 2;
printf("%d", ans);
}
int main() {
//cin.tie(0);
//cout.tie(0);
solve();
return 0;
}
被3整除的子序列
假设我们有一个字符串456,其字串构成可以从前往后遍历,每次在之前的子串前加上该位置的字符,再将此字符加入
| 当前位置 | 子串 |
|---|---|
| 1 | 4 |
| 2 | 4,45,5 |
| 3 | 4,45,5,46,456,56,6 |
那么对于该题,我们可以考虑每一位除以3后的余数
若一个数取余3为1,另一个数取余3为0,那么这俩个数组合起来取余3是为1的,其他的依次类推
对数组dp[][3],一维i为当前位置
dp[i][0]保存其除以3后余0,即被3整除的数的字串个数,dp[i][1]保存其被3后余1的字串个数,dp[i][2]保存其被3后余1的字串个数
那么可得到状态转移方程为
若当前字符取余3后为0,则有:
dp[i][0] = 2 * dp[i - 1][0] + 1
dp[i][1] = dp[i - 1][1] * 2
dp[i][2] = dp[i - 1][2] * 2
若当前字符取余3后为1,则有:
dp[i][0] = dp[i - 1][0] + dp[i - 1][2]
dp[i][1] = dp[i - 1][0] + dp[i - 1][1] + 1
dp[i][2] = dp[i - 1][1] + dp[i - 1][2]
若当前字符取余3后为2,则有:
dp[i][0] = dp[i - 1][0] + dp[i - 1][1]
dp[i][1] = dp[i - 1][2] + dp[i - 1][1]
dp[i][2] = dp[i - 1][2] + dp[i - 1][0] + 1
最后答案即为dp[最后一次处理位置][0]
代码:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
const int N = 5e4 + 7;
const int Maxx = 2e5 + 7;
const ll mod = 1e9+7;
#define x first
#define y second
string s;
ll dp[57][3];
void solve()
{
cin >> s;
dp[0][(s[0] - '0') % 3] = 1;
for (int i = 1; i <= s.size(); i++)
{
int tt = (s[i] - '0') % 3;
if (tt == 0) {
dp[i][0] = (2 * dp[i - 1][0] + 1) % mod;
dp[i][1] = (dp[i - 1][1] * 2 ) % mod;
dp[i][2] = (dp[i - 1][2] * 2 ) % mod;
}
else if (tt == 1) {
dp[i][0] = (dp[i - 1][0] + dp[i - 1][2]) % mod;
dp[i][1] = (dp[i - 1][0] + dp[i - 1][1] + 1) % mod;
dp[i][2] = (dp[i - 1][1] + dp[i - 1][2]) % mod;
}
else if(tt==2) {
dp[i][0] = (dp[i - 1][0] + dp[i - 1][1]) % mod;
dp[i][1] = (dp[i - 1][2] + dp[i - 1][1]) % mod;
dp[i][2] = (dp[i - 1][2] + dp[i - 1][0] + 1) % mod;
}
}
cout << dp[s.size() - 1][0];
}
int main()
{
cin.sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
}
最短路
其实就是一个spfa的模板题,spfa可以处理负边权
图的存储方式推荐用链式向前星,vector<>来模拟,因为若点数大于等于1e5的情况下,用邻接矩阵,一般会爆空间
代码:
vector处理:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
const int N = 2e4 + 7;
ll dis[N];
vector<pair<int, int>> G[N];
int n, m;
int vis[N];
void spfa()
{
queue<int> q;
q.push(1);
vis[1] = 1;
while (!q.empty())
{
int tt = q.front();
q.pop();
vis[tt] = 0;
for (int i = 0; i < G[tt].size(); i++)
{
int u = G[tt][i].first;
int x = G[tt][i].second;
if (dis[u] > x + dis[tt]) {
if (!vis[u]) q.push(u), vis[u] = 1;
dis[u] = dis[tt] + x;
}
}
}
}
void solve()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) dis[i] = 1e18 + 7;
dis[1] = 0;
for (int i = 0; i < m; i++)
{
int v1, v2,w;
scanf("%d%d%d", &v1, &v2, &w);
G[v1].push_back({ v2,w });
}
spfa();
for (int i = 2; i <= n; i++)
printf("%lld\n", dis[i]);
}
int main() {
solve();
return 0;
}
链式向前星处理:
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#include<bitset>
typedef long long ll;
using namespace std;
const int N = 6 * 1e5 + 7;
const int INF = 0x3f3f3f3f;
struct node {
int u, ne;
ll w;
}edge[N];
int fa[20007];
int n, m;
ll dis[20007];
int cnt;
int u, v, w;
bool vis[20007];
inline void add(int u, int v, int w)
{
edge[++cnt].u = v;
edge[cnt].w = w;
edge[cnt].ne = fa[u];
fa[u] = cnt;
}
inline void spfa(int v)
{
queue<int>q;
q.push(v);
while (!q.empty())
{
int fr = q.front();
q.pop();
vis[fr] = 0;
for (int i = fa[fr]; i; i = edge[i].ne)
{
if (dis[edge[i].u] > dis[fr] + edge[i].w)
{
dis[edge[i].u] = dis[fr] + edge[i].w;
if (!vis[edge[i].u]) {
vis[edge[i].u] = 1;
q.push(edge[i].u);
}
}
}
}
}
inline void deal()
{
scanf("%d%d", &n, &m);
for (int i = 2; i <= n; i++) dis[i] = INF;
for (int i = 0; i < m; i++)
{
scanf("%d%d%lld", &u, &v, &w);
add(u, v, w);
}
spfa(1);
for (int i = 2; i <= n; i++) printf("%lld\n", dis[i]);
}
int main()
{
deal();
}
/*
*/
浙公网安备 33010602011771号