A
做法:模拟
这里给的计算器操作都是可逆的。那么只要注意中间会爆longlong用int128存就好,比赛的时候因为这个东西爆了两发...
#include <bits/stdc++.h>
using namespace std;
namespace io {
#define in(a) a=read()
#define out(a) write(a)
#define outn(a) out(a),putchar('\n')
#define I_int __int128
inline I_int read() {
I_int x = 0 , f = 1 ; char c = getchar() ;
while( c < '0' || c > '9' ) { if( c == '-' ) f = -1 ; c = getchar() ; }
while( c >= '0' && c <= '9' ) { x = x * 10 + c - '0' ; c = getchar() ; }
return x * f ;
}
char F[ 200 ] ;
inline void write( I_int x ) {
if( x == 0 ) { putchar( '0' ) ; return ; }
I_int tmp = x > 0 ? x : -x ;
if( x < 0 ) putchar( '-' ) ;
int cnt = 0 ;
while( tmp > 0 ) {
F[ cnt ++ ] = tmp % 10 + '0' ;
tmp /= 10 ;
}
while( cnt > 0 ) putchar( F[ -- cnt ] ) ;
}
#undef I_int
}
using namespace io ;
#define N 110
#define ll __int128
int n;
ll x;
ll opt[N];
ll a[N];
int main() {
scanf("%d", &n);
x = read();
for(int i = 1; i <= n; ++i) {
opt[i] = read(), a[i] = read();
}
for(int i = n; i; i--) {
if(opt[i] == 1) x = (__int128)(x - a[i]);
if(opt[i] == 2) x = (ll)(x + a[i]);
if(opt[i] == 3) x = (ll)(x / a[i]);
if(opt[i] == 4) x = (ll)(x * a[i]);
}
outn(x);
return 0;
}
B
做法:贪心
猜的结论是0后面能放4就优先放4,4后面能优先放0就放0,2后面能优先放0就放0,这样就过了,貌似和标算做法不一样,不过应该是对的。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 100010
ll ans = 0;
int n, a[N], cnt[5], f[N];
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]), cnt[a[i]]++;
for(int i = 1; i <= n; ++i) {
if(f[i - 1] == 0) {
if(cnt[4]) cnt[4]--, ans += 16, f[i] = 4;
else if(cnt[2]) cnt[2]--, ans += 4, f[i] = 2;
else if(cnt[0]) cnt[0]--, f[i] = 0;
continue;
}
if(f[i - 1] == 2) {
if(cnt[0]) cnt[0]--, ans += 4, f[i] = 0;
else if(cnt[4]) cnt[4]--, ans += 4, f[i] = 4;
else if(cnt[2]) cnt[2]--, f[i] = 2;
continue;
}
if(f[i - 1] == 4) {
if(cnt[0]) cnt[0]--, ans += 16, f[i] = 0;
else if(cnt[2]) cnt[2]--, ans += 4, f[i] = 2;
else if(cnt[4]) cnt[4]--, f[i] = 4;
}
}
printf("%lld\n", ans);
return 0;
}
C
做法:dp
赛时想了一个dp然后自行hack掉了于是写D去了。
赛后发现数据太水这个明显错误的dp也可以过。
果然我dp还是菜,完全没想到正解。
将原序列排序一遍,那么每个数可以转移的区间就是以它为起点的后缀,设\(f[i][j]\)表示当前在点i,耐久度为j是否可行,分为走这里和不走这里两种情况转移(注意如果前后两个点价值相同那肯定不走),然后类似01背包那样子转移。
注意dp数组要第二维要开大一点(至少要大于6000),然后用bool存
#include <bits/stdc++.h>
using namespace std;
bool f[3010][10010];
int n;
struct Node {
int id, val;
}a[3010];
bool cmp(Node a, Node b) { return a.val > b.val; }
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; ++i) scanf("%d", &a[i].val), a[i].id = i;
sort(a + 1, a + n + 1, cmp);
int l;
for(int i = 1; i <= n; ++i)
if(a[i].id == 1) {
l = i;
f[i][a[i].val] = 1;
break;
}
for(int i = l + 1; i <= n; ++i) {
if(a[i].id == n) {
l = i;
for(int j = 6010; j >= 0; --j) f[i][j] |= f[i - 1][j ^ a[i].val];
break;
}
if(a[i].val == a[i - 1].val) {
for(int j = 0; j <= 6010; ++j) f[i][j] |= f[i - 1][j];
} else {
for(int j = 0; j <= 6010; ++j) f[i][j] |= f[i - 1][j], f[i][j] |= f[i - 1][j ^ a[i].val];
}
}
for(int i = 6010; i; --i)
if(f[l][i]) return printf("%d\n", i), 0;
puts("-1");
}
D
做法:欧拉函数
用容斥也是可以算的但是不会。(一位大佬:这不是入门容斥吗)
由\(gcd(x,n)=gcd(n-x,n)\)可知与n互质的数一定是成对出现的,而且两人从两端走所以x和n-x一定同时走到...(赛时就没想到这个),每对互质的数一共会给两人分别带来\(k^{n}\)的收益。也就是说每个人的总收益是\(k^{\frac{\phi(n)}{2}*n}\)(与n互质的数的和为\(\frac{\phi(n)}{2}*n\)),于是直接这样算出来这个值然后乘A+B就行了。比赛时没想到x和n-x一定同时走到于是暴力处理出来每个和它互质的数然后直接算...
其实就是把公式展开了而已,不过也有90分。
关于上面的公式的证明,可以戳这里
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 3162278
const ll mod = 1e9 + 7;
ll n, k, A, B, cnt = 0;
ll power(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
int main() {
scanf("%lld%lld%lld%lld", &n, &k, &A, &B);
ll m = n, phi = n;
for(ll i = 2; i * i <= m; ++i) {
if(m % i == 0) {
while(m % i == 0) m /= i;
phi = phi / i * (i - 1);
}
if(m == 1) break;
}
if(m > 1) phi = phi / m * (m - 1);
printf("%lld\n", ((A + B) % mod) * (power(k % mod, phi / 2 * n) % mod) % mod);
}
90分暴力
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 5000100
const ll mod = 1e9 + 7;
ll n, k, A, B, cnt = 0;
ll a[N];
ll power(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = (__int128)ans * a % mod;
a = (__int128)a * a % mod;
b >>= 1;
}
return ans;
}
ll gcd(ll a, ll b) {
if(!b) return a;
return gcd(b, a % b);
}
int main() {
scanf("%lld%lld%lld%lld", &n, &k, &A, &B);
//ll phi = mod - 1;
cnt = 0;
for(ll i = 1; i <= n; ++i)
if(gcd(n, i) == 1) {
a[++cnt] = i;
// a[++cnt] = n - i;
// if(cnt > (int)(1e6)) while(1) puts("233");
}
ll a1 = 1, b1 = 1; k %= mod;
for(ll i = 1; i <= cnt; ++i) {
a1 = (__int128)a1 * power(k, a[i]) % mod;
// a1 = (__int128)a1 * power(k, n - a[i]) % mod;
// b1 = (__int128)b1 * power(k, a[i]) % mod;
b1 = (__int128)b1 * power(k, n - a[i]) % mod;
}
A %= mod; B %= mod;
A = (__int128)A * a1 % mod; B = (__int128)B * a1 % mod;
printf("%lld\n", (A % mod + B % mod) % mod);
}
其他题不会了。可能会补一下G题的题解
官方题解戳这里
提取码是k8xd