A.两只脑斧(签到题)
这题就不多叙述,直接上代码
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <vector> using namespace std; int main(){ char ss[5]; char p[8]={'X','E','I','E','I','E','I','I'}; int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",ss); int len = strlen(ss); for(int i=0;i<len;i++) { if(ss[i]=='+'||ss[i]=='-')continue; printf("%c",p[ss[i]-'0']); } } return 0; }
K.多项式求导(签到题)
这题注意取模问题,(每个地方都取模就完事了)
#include<bits/stdc++.h> using namespace std; #define maxn 300005 #define ll long long int n,m; ll a[maxn]; const int mod=998244353; int main() { scanf("%d %d",&n,&m); for(int i=n;i>=0;i--) scanf("%lld",&a[i]); int nn=n; while(m--){ for(int i=0;i<=nn-1;i++) a[i]=a[i+1]*(i+1)%mod; nn--; } for(int i=n;i>nn;i--) printf("0 "); for(int i=nn;i>=0;i--) printf("%lld ",a[i]%mod); return 0; }
F.风王之瞳
这题较前两题难度就明显提升,这里提供两种做法:
- 找规律
你把前几种情况都算一遍,最后会发现一个规律:
int k=min(n,m);
for(int i=1;i<=k;i++)
{
sum=sum+(m-i+1)*(n-i+1)*i;
}
- 分为多种情况计算
1–最普通的正方形
这里有个公式:在一个正方形内(参照上图),它的正方形个数为
(2n+1)(n+1)n / 6;
2–立着的正方形
这里就需要把每种情况考虑到,再把他们加在一起即可。
附上AC代码:
#include<bits/stdc++.h> using namespace std; #define ll long long ll f(int n, int m){ ll ans = 0; int k = min(n, m); if(k == 1) return max(n, m); ans += ((2*k+1)*(k+1)*k)/6; if(n == m) return ans; else if(n > m){ return ans * (n - m + 1) - f(k-1, m)*(n-m); } else if(m > n){ return ans * (m - n + 1) - f(k-1, n)*(m-n); } } int main() { int n, m, t; scanf("%d", &t); while(t--){ ll ans = 0; scanf("%d %d", &n, &m); for(int i = 2 ; i <= min(n, m) ; i += 2){ ans += (n-i+1)*(m-i+1); } for(int i = 3 ; i <= min(n, m) ; i ++){ ans += (n-i+1)*(m-i+1)*((i-1)/2)*2; } cout << f(n, m) + ans << endl; } return 0; }
H.目标是成为数论大师
这题要注意√ax的问题,因为a,x都是在根号里,因此ax>=0,所以求得两个解时要判断a*x是否>=0.
#include<bits/stdc++.h> using namespace std; #define maxn 300005 #define ll long long int ans[3], cnt; double f1(int a, int b){ return ((2*b+a)-sqrt((2*b+a)*(2*b+a)-4*b*b))/2; } double f2(int a, int b){ return ((2*b+a)+sqrt((2*b+a)*(2*b+a)-4*b*b))/2; } int main() { int t, a, b; scanf("%d", &t); while(t--){ memset(ans, 0, sizeof(ans)); cnt = 0; scanf("%d %d", &a, &b); if((2*b+a)*(2*b+a)-4*b*b == 0){ double d = f1(a, b); if(d*a >= 0){ for(int i = d - 1 ; i <= d + 1 ; ++ i){ if(sqrt(a*i) + b == i){ ans[++cnt] = i; break; } } } cout << cnt << endl; for(int i = 1 ; i <= cnt ; ++ i) printf("%d%c", ans[i], i == cnt ? ' ' : ' '); } else if((2*b+a)*(2*b+a)-4*b*b > 0){ double d = f1(a, b); if(d*a >= 0){ d = (int)d; for(int i = d - 1 ; i <= d + 1 ; ++ i){ if(sqrt(a*i) + b == i){ ans[++cnt] = i; break; } } } d = f2(a, b); if(d*a >= 0){ d = (int)d; for(int i = d - 1 ; i <= d + 1 ; ++ i){ if(sqrt(a*i) + b == i && ((cnt == 1 && ans[1] != i) || cnt == 0)){ ans[++cnt] = i; break; } } } cout << cnt << endl; for(int i = 1 ; i <= cnt ; ++ i) printf("%d%c", ans[i], i == cnt ? ' ' : ' '); } } return 0; }
C - 赛尔逵传说
这题本质上是一个贪心题,要先把攻击力大的怪放前面,哪怕吃果子也要先把他打掉,因为你打一个攻击力小的怪和打一个攻击力大的怪对方的掉血数是一样的,因此要将你的果子效果最大化。
这里还要注意能否整除的问题…
!!!!注意
这题一定一定要把结构体内的参量改为long long,不然数据会把你卡掉
#include<bits/stdc++.h> using namespace std; #define maxn 300005 #define ll long long int n,k,c; ll sum; struct gs{ ll d,x; }a[maxn]; bool cmp(gs a,gs b){ return a.x>b.x; } int main() { scanf("%d %d %d",&n,&k,&c); for(int i=0;i<n;i++) scanf("%d %d",&a[i].d,&a[i].x); sort(a,a+n,cmp); for(int i=0;i<n;i++){ if(a[i].d<=k)continue; else{ if(a[i].d-k<=k*c){ if(a[i].d%k==0)c-=a[i].d/k-1; else c-=a[i].d/k; } else{ a[i].d-=k*c+k; c=0; ll t=a[i].d/k; if(a[i].d%k==0)sum+=a[i].x*t; else sum+=a[i].x*(t+1); } } } printf("%lld",sum); return 0; }
E. 只有一端开口的瓶子
这题你推过一些样例后就会发现无论那种情况,最多只会用到两个栈,你只需要判断下一个数是不是你需要的数即可
#include<bits/stdc++.h> using namespace std; #define ll long long #define maxn 300005 int t, n, top; int a[maxn], b[maxn]; int main() { scanf("%d", &t); while(t--){ scanf("%d", &n); for(int i = 1 ; i <= n ; ++ i){ scanf("%d", &a[i]); } int top = 1, p = 1; for(int i = 1 ; i <= n ; ++ i){ b[top] = a[i]; while(b[top] == p){ p ++; top --; } top ++; } if(top == 1) cout << "1" << endl; else cout << "2" << endl; } return 0; }
J. 金色传说
这道题是一道非常非常棒的数学题
当 n == 1 || n == 2 时,显然不会有运算符出现,直接计算即可
但是当 n >= 3 时该怎么办呢?
我们先来看看n == 3 的情况吧~
sum(0,999)+
sum(0——>9,‘+’,0——>9)+
sum(0——>9,‘-’,0——>9);
这里我们很容易就能发现 a + b 和 a - b 后面的部分都被抵消了,最后留下的其实只是前面部分的两倍!!!
我们继续往下推,就会得到这样一个重要结论——对于统计答案,只有整个串中的第一个数字对答案是有贡献的。
知道了只有第一个出现的数对答案有贡献,那么可以枚举第一个出现运算符的位置。以这个运算符为界,前面是第一个出现的数字,后面是一个任意的算式,两者是相互独立的。记所有的 k 位数字的和为 sum[k],记
所有长度为 k 算式的个数为 num[k],那么答案即为
至于 sum[n] 可以很容易用等差数列求和得到
而 num[k] 部分可以考虑同样的思路,即枚举第一个运算符位置,则
令 j = i -1 ,则
令 j = i ,则
联立。
不难发现只有 j = 1和2 时需要特别计算,其他部分可以直接从num[k] 得到,即
num[ k ] = 10 * num[ k - 1 ] + 20 * num[ k -2 ];
线性递推即可。
时间复杂度 O(n)。
#include<bits/stdc++.h> using namespace std; #define maxn 500005 #define ll long long const ll mod=998244353; int t; ll s[maxn],num[maxn]; ll poww(ll a,ll b){ ll ans=1,base=a%mod; while(b!=0){ if(b&1!=0)ans=(ans*base)%mod; base=(base*base)%mod; b>>=1; } return ans%mod; } int main() { num[1]=10; num[2]=100; s[1]=45; s[2]=4950; for(int i=3;i<=500001;i++){ num[i]=(10*num[i-1]+20*num[i-2])%mod; s[i]=(poww(10,i)*(poww(10,i)-1)/2)%mod; } scanf("%d",&t); while(t--){ int n; scanf("%d",&n); ll ans=s[n]; for(int i=2;i<=n-1;i++){ ans=ans+2*s[i-1]*num[n-i]; ans%=mod; } printf("%lld ",ans); } return 0; }