return 0;是个好习惯,在打蓝桥别的时候希望都加上!
我安慰我自己,没事,明年还有一次机会,咱们再接再厉!
参考答案:1478
#include
using namespace std;
const int N=10010;
int a[N];
int main()
{
cout<<9*9*9*2+9*2+2<<endl;
return 0;
}
参考答案:14
这个答案我也不确定,我看到网上也有人给的参考答案是4,因为没有算012,我这里算了012,所以答案是14
0120、0121、0122、0123、0124、0125、0126、0127、0128、0129、1230、1231、1012、1123.
也可以是编程写法:y
#include
#include
#include
using namespace std;
const int months[] = {
0, 31, 28, 31, 30, 31,
30, 31, 31, 30, 31, 30,
31
};
bool check(string str)
{
for (int i = 0; i + 2 < str.size(); i ++ )
if (str[i + 1] == str[i] + 1 && str[i + 2] == str[i] + 2)
return true;
return false;
}
int main()
{
int year = 2022, month = 1, day = 1;
int res = 0;
for (int i = 0; i < 365; i ++ )
{
char str[10];
sprintf(str, "%04d%02d%02d", year, month, day);
if (check(str))
{
res ++ ;
cout << str << endl;
}
if ( ++ day > months[month])
{
day = 1;
month ++ ;
}
}
cout << res << endl;
return 0;
}
sprintf最常见的应用之一莫过于把整数打印到字符串中,所以,spritnf 在大多数场合可以替代itoa(把一个整数转换为字符串)。如:
// 把整数123打印成一个字符串保存在s中。
sprintf(s, "%d", 123); // 产生"123"
可以指定宽度,不足的左边补空格
sprintf(s, "%8d%8d", 123, 4567); // 产生:" 123 4567"
当然也可以左对齐
sprintf(s, "%-8d%8d", 123, 4567); // 产生:"123 4567"
也可以按照16进制打印
sprintf(s, "%8x", 4567); // 小写16进制,宽度占8个位置,右对齐
sprintf(s, "%-8X", 4568); // 大写16进制,宽度占8个位置,左对齐
2、控制浮点数打印格式
和printf的用法是一样的
3、连接字符串
char *who = "I";
char *whom = "52PHP";
sprintf(s, "%s love %s.", who, whom); // 产生:"I love 52PHP. "
或者
sprintf(s, "%.7s%.7s", a1, a2); // 产生:"ABCDEFGHIJKLMN"
4、打印地址信息
5、利用sprintf的返回值
详情可看大佬的博客!!!
#include
using namespace std;
typedef long long ll;
int main()
{
long long a,b,n;
scanf("%lld%lld%lld",&a,&b,&n);
ll total=a*5+b*2;
ll ans=n/total;//学习的星期数
ll res=n%total;//剩下的数
ll d=0;
for(int i=0;i<5;i++)
{
if(res>0)
{
res-=a;
d++;
}
else break;
}
if(res>0)
{
for(int i=0;i<2;i++)
{
if(res>0)
{
res-=b;
d++;
}
else break;
}
}
d+=ans*7;
printf("%lld",d);
return 0;
}
写法二:y
#include
#include
#include
using namespace std;
typedef long long LL;
int main()
{
LL a, b, n;
cin >> a >> b >> n;
LL s = 5 * a + 2 * b;
LL res = n / s * 7;
n %= s;
LL d[] = {a, a, a, a, a, b, b};
for (int i = 0; n > 0; i ++ )
{
n -= d[i];
res ++ ;
}
cout << res << endl;
return 0;
}
看数据范围,就知道不用考虑n==1的时候
#include
using namespace std;
const int N=10010;
int a[N];
int main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);cout.tie(0);
int n;
cin>>n;
int l=1,r=n;
for(int i=1;i<=n;i++)
{
a[i]=max((i-l)*2,(r-i)*2);
}
for(int i=1;i<=n;i++)
cout<<a[i]<<endl;
return 0;
}
这道题目我卡的点就是没考虑到a的某位-b的某位可能是负数!且不能纯暴力,这样子会tle。
1、(res+MOD)%MOD可以保证为非负数
2、max可以比较三个数,但是要加上大括号{(a,b,c)},然后,也可以比较vector里面的最大值
y:秦九韶算法
#include
#include
#include
using namespace std;
typedef long long LL;
const int N = 100010, MOD = 1000000007;
int n, m1, m2, m;
int a[N], b[N];
int main()
{
scanf("%d", &n);
scanf("%d", &m1);
//我们这里从后往前存放数据,有点像高精度加法的存储方式
for (int i = m1 - 1; i >= 0; i -- ) scanf("%d", &a[i]);
scanf("%d", &m2);
for (int i = m2 - 1; i >= 0; i -- ) scanf("%d", &b[i]);
int m = max(m1, m2);
int res = 0;
for (int i = m - 1; i >= 0; i -- )
res = (res * (LL)max({2, a[i] + 1, b[i] + 1}) + a[i] - b[i]) % MOD;//秦九韶算法
printf("%d\n", res);//(res+MOD)%MOD可以保证为非负数,但是我们在前面已经确保啦
return 0;
}
#include
#include
using namespace std;
// 加引用避免再拷贝整个数组
vector<int> add(vector<int> &A, vector<int> &B)
{
// 定义储存结果的vector以及进位t,第0位没有进位->初始化为0
vector<int> C;
int t = 0;
// 从个位开始遍历直至遍历完A和B的所有位
for (int i = 0; i < A.size() || i < B.size(); i++)
{
// 每一次用t表示Ai,Bi与上一个数的进位这三个数的和
if(i < A.size()) t += A[i];
if(i < B.size()) t += B[i];
// 当前这一位输出t除以10的余数
C.push_back(t % 10);
// t是否进位
t /= 10;
}
// 如果最高位有进位则补1
if(t) C.push_back(1);
return C;
}
int main()
{
// 使用字符串读入
string a, b;
vector<int> A, B;
cin >> a >> b; //a = "123456"
// 使用vector逆序读入,变成整数需要减去偏移量0
for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');//A = [6,5,4,3,2,1]
for (int i = b.size() - 1; i >= 0; i--) B.push_back(b[i] - '0');
// 相当于vector
auto C = add(A, B);
// 倒序输出
for (int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]);
return 0;
}
// 个位放在索引0的位置:出现进位的情况时需要在高位补上1,这样在数组后端补数比较容易
我的做法:出现了错误
略暴力
#include
using namespace std;
const int N=1010;
const long long MOD=1000000007;
int a[N],b[N],c[N];
int main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);cout.tie(0);
int n,x;
scanf("%d",&n);
int A;
scanf("%d",&A);//第一个数的位数
for(int i=0;i<A;i++)
{
scanf("%d",&x);
a[A-i]=x;
}
int B;
scanf("%d",&B);//第二个数的位数
for(int j=0;j<B;j++)
{
scanf("%d",&x);
b[B-j]=x;
}
int ansA=0,ansB=0;
c[0]=1;
for(int i=1;i<=max(A,B);i++)
{
c[i]=max(2,max(a[i],b[i])+1);
c[i]*=c[i-1]%MOD;
ansA+=c[i-1]*a[i]%MOD;
ansB+=c[i-1]*b[i]%MOD;
}
int ans =(ansA-ansB)%MOD;
printf("%d",ans);
return 0;
}
由于能用一维前缀和就用一维前缀和,像这种竞赛题目,一般都会卡常数。
然后数据范围是500,所以时间复杂度最大是 O ( n 3 ) O(n^3) O(n3)。
这里用到双指针,但是如果这里的数可能是负数的话,那么我就要考虑用平衡树啊,树状数组啊那些东西。
答案可能会爆int
C 5 2 C_5^2 C52 = 510 ∗ 255 = 130550 =510*255=130550 =510∗255=130550的平方就是int最大值
下面的代码可以看这个图片来理解。
慢指针l 继续前进(如图),直到 子矩阵的和 不大于k,慢指针没必要前进了,因为该子矩阵的所有宽度为 j - i + 1 的子矩阵(总共 r- l + 1 种)一定满足要求,更新该情况对答案的贡献 r - l+ 1;反之,如果慢指针r越界(r > l),则不操作,直接进入下层循环.
y:。
#include
using namespace std;
typedef long long ll;
const int N = 5e2+3;
int n, m, k;
int a[N][N];
int main(){
ios::sync_with_stdio(false);
cin >> n >> m >> k;
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
cin >> a[i][j];
a[i][j] += a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];
}
}
ll ans = 0;
for(int i=1; i<=m; i++){
for(int j=i; j<=m; j++){
for(int l = 1, r = 1; r <= n; r ++ ){
while(l <= r && a[r][j] - a[l - 1][j] - a[r][i - 1] + a[l - 1][i - 1] > k) l ++ ;
if(l <= r) ans +=r - l + 1;
}
}
}
cout << ans << '\n';
}
我的tle做法:
#include
using namespace std;
typedef long long ll;
const int N=1010;
int a[N][N];
int s[N][N];
int main()
{
// freopen("in.txt","r",stdin);
int n,m;
ll k;
int ans=0;
scanf("%d%d%lld",&n,&m,&k);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
if(a[i][j]<=k) ans++;//1*1的矩阵
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];//二位前缀和矩阵
//先来个暴力,拿部分分
// for(int i=1;i<=n;i++)
// for(int j=1;j<=m;j++)
// cout<
for(int i=1;i<n;i++)
for(int j=1;j<m;j++)
{
for(int p=i;p<=n;p++)
for(int q=j;q<=m;q++)
{
if(i==p&&j==q)continue;
// cout<
// cout<
if((s[p][q]-s[p][j-1]-s[i-1][q]+s[i-1][j-1])<=k)
ans++;
}
}
cout<<ans<<endl;
return 0;
}
类似题目!蒙德里安的梦想–状压dp
写法一:
图解题解,还是蛮清楚的!!牛!
#include
using namespace std;
const int N = 1e7+10, MOD = 1000000007;
int f[N];
int main()
{
f[1] = 1;
f[2] = 2;
f[3] = 5;
int n;
cin >> n;
for(int i = 4; i <= n; i ++)
{
f[i] = (2*f[i-1]%MOD+f[i-3]%MOD)%MOD;
}
cout << f[n];
return 0;
}
写法二:
递推思想牛!
#include
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 1E7 + 10, mod = 1000000007;
int a[N]; // 当然你可以选择不开数组.
int main()
{
int n; cin >> n;
a[1] = 1, a[2] = 2, a[3] = 5;
for (int i = 4; i <= n; ++i) {
a[i] = a[i - 1]; // 加一列在后面
a[i] = (a[i] + a[i - 2]) % mod;
a[i] = (0ll + a[i] + a[i - 3] * 2) % mod;
}
cout << a[n] << endl;
return 0;
}
#include
#include
#include
using namespace std;
const int N = 1e7 + 10, MOD = 1e9 + 7;
int n;
int g[4][4] = {
{1, 1, 1, 1},
{0, 0, 1, 1},
{0, 1, 0, 1},
{1, 0, 0, 0},
};
int f[2][4];
int main()
{
scanf("%d", &n);
f[1][0] = 1;
for (int i = 1; i <= n; i ++ )
{
memset(f[i + 1 & 1], 0, sizeof f[0]);//滚动数组,优化空间
for (int j = 0; j < 4; j ++ )
for (int k = 0; k < 4; k ++ )
f[i + 1 & 1][k] = (f[i + 1 & 1][k] + f[i & 1][j] * g[j][k]) % MOD;//这个乘法这里也可以优化
}
printf("%d\n", f[n + 1 & 1][0]);
return 0;
}
这道题目是个图论.由于这个是有向边,不能用并查集。
图的遍历问题:dfs、bfs
#include
using namespace std;
const int N=200003;//比2e5大的第一个质数
const int null=0x3f3f3f3f;
int h[N];
int find(int x)
{
int k=(x%N+N)%N;
while(h[k]!=null&&h[k]!=x)
{
k++;
if(k==N)k=0;
//这个时候我们已经看完了,就要重头开始
}
return k;//要么是找到空位,要么是找到x
}
int main()
{
int n;
scanf("%d",&n);
memset(h,0x3f,sizeof h);
while(n--)
{
char op[2];
int x;
scanf("%s%d",op,&x);
int k=find(x);
if(*op=='I')
h[k]=x;
else {
if(h[k]!=null) //如果是找到x
puts("Yes");
else puts("No");//如果是找到空位
}
}
return 0;
}
手写哈希表会比unordered_map快一些。
哈希表是将一个(x,y)转化为一个比较小的正数的。
如果多个雷在同一个点的话,那我们就保留爆炸范围最大的点
#include
#include
#include
using namespace std;
typedef long long LL;
const int N = 50010, M = 999997;
int n, m;
struct Circle
{
int x, y, r;
}cir[N];
LL h[M];//哈希表
int id[M];
bool st[M];
LL get_key(int x, int y)
{
return x * 1000000001ll + y;
}
int find(int x, int y)
{
LL key = get_key(x, y);
int t = (key % M + M) % M;
while (h[t] != -1 && h[t] != key)
if ( ++ t == M)
t = 0;
return t;
}
int sqr(int x)
{
return x * x;
}
void dfs(int x, int y, int r)
{
st[find(x, y)] = true;
for (int i = x - r; i <= x + r; i ++ )
for (int j = y - r; j <= y + r; j ++ )
if (sqr(i - x) + sqr(j - y) <= sqr(r))
{
int t = find(i, j);
if (id[t] && !st[t])
dfs(i, j, cir[id[t]].r);
}
}
int main()
{
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
for (int i = 1; i <= n; i ++ )
{
int x, y, r;
scanf("%d%d%d", &x, &y, &r);
cir[i] = {x, y, r};
int t = find(x, y);
if (h[t] == -1) h[t] = get_key(x, y);
if (!id[t] || cir[id[t]].r < r)
id[t] = i;
}
while (m -- )
{
int x, y, r;
scanf("%d%d%d", &x, &y, &r);
for (int i = x - r; i <= x + r; i ++ )
for (int j = y - r; j <= y + r; j ++ )
if (sqr(i - x) + sqr(j - y) <= sqr(r))
{
int t = find(i, j);
if (id[t] && !st[t])
dfs(i, j, cir[id[t]].r);
}
}
int res = 0;
for (int i = 1; i <= n; i ++ )
if (st[find(cir[i].x, cir[i].y)])
res ++ ;
printf("%d\n", res);
return 0;
}
应该算是我的错误暴力写法了哈哈哈
#include
using namespace std;
const int N=50010;
struct B{
int x,y,r;
bool k;
bool operator<(const B&t)const
{
if(t.x!=x)return x<t.x;
else return y<t.y;
}
};
B a[N];
int dist(int x1,int y1,int x2,int y2)
{
int res=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
return res;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,m,x,y,r,ans=0;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>x>>y>>r;
a[i].x=x,a[i].y=y,a[i].r=r;
}
sort(a+1,a+n+1);
while(m--)
{
cin>>x>>y>>r;
for(int i=1;i<=n;i++)
{
int tt=dist(a[i].x,a[i].y,x,y);
if(tt>10)break;
if(a[i].k==false&&tt<r)
{
ans++;
a[i].k=true;
for(int j=i;j<=n;j++)
{
int kk=dist(a[i].x,a[i].y,a[j].x,a[j].y);
if(kk>10)break;
if(a[j].k==false&&kk<a[i].r)
{
ans++;
a[j].k=true;
}
}
}
}
}
cout<<ans<<endl;
return 0;
}
#include
#include
#include
using namespace std;
const int N = 110, MOD = 1e9 + 7;
int n, m;
int f[N][N][N];
int main()
{
cin >> n >> m;
f[0][0][2] = 1;
for (int i = 0; i <= n; i ++ )
for (int j = 0; j <= m; j ++ )
for (int k = 0; k <= m; k ++ )
{
int& v = f[i][j][k];
if (i && k % 2 == 0) v = (v + f[i - 1][j][k / 2]) % MOD;
if (j) v = (v + f[i][j - 1][k + 1]) % MOD;
}
cout << f[n][m - 1][1] << endl;
return 0;
}
一个数只能变小,不能变大,所以我们就从最大的数开始入手,然后,可以用贪心的算法。
我们可以用优先队列来写,在优先队列里面维护一段区间。v和区间左端点是我们的双端点排序。
第二个写法比第一个写法好理解、且运行速度快一些!
写法一:O(6nlogn)
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int N = 200010;
int n;
LL h[N];
struct Seg
{
int l, r;
LL v;
bool operator< (const Seg& S) const
{
if (v != S.v) return v < S.v;
return l > S.l;
}
};
LL f(LL x)
{
return sqrt(x / 2 + 1);
}
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%lld", &h[i]);
priority_queue<Seg> heap;
for (int i = 0; i < n; i ++ )
{
int j = i + 1;
while (j < n && h[i] == h[j]) j ++ ;
heap.push({i, j - 1, h[i]});
i = j - 1;
}
int res = 0;
while (heap.size() > 1 || heap.top().v > 1)
{
auto t = heap.top();
heap.pop();
while (heap.size() && heap.top().v == t.v && t.r + 1 == heap.top().l)
{
t.r = heap.top().r;
heap.pop();
}
heap.push({t.l, t.r, f(t.v)});
if (t.v > 1) res ++ ;
}
printf("%d\n", res);
return 0;
}
写法二:O(6n)
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int N = 200010, M = 10;
int n, m;
LL f[N][M];
int main()
{
scanf("%d", &n);
LL stk[M];
int res = 0;
for (int i = 0; i < n; i ++ )
{
LL x;
int top = 0;
scanf("%lld", &x);
while (x > 1) stk[ ++ top] = x, x = sqrt(x / 2 + 1);
res += top;//记录他的步长
m = max(m, top);
for (int j = 0, k = top; k; j ++, k -- )
f[i][j] = stk[k];
}
for (int i = 0; i < m; i ++ )
for (int j = 1; j < n; j ++ )
if (f[j][i] && f[j][i] == f[j - 1][i])
res -- ;
printf("%d\n", res);
return 0;
}
这一次做的很感觉做的很赶,很多题目都是暴力写出来的,然后本来打算把能写的弄完之后再回头看看改一下的,根本不给我这机会,好家伙!
能力的确有待提高,知道都是很基础的题,呜呜呜,我们学校的金牌爷提前一个半小时就走了,真的是慕了,自己要继续努力哇!