5.31考试+总结
5.31
T1 icecream
- 裸的多重背包,卡常这种不人道的东西已经不想再多说什么了,按模数分类,我竟然傻叉到对每一个模数都开一个单调队列,还好内存够用,为了防止爆内存分类讨论还写挂了,极限数据没拍,在oj上跑T成了10分(其实后面应该全wa掉的才对),在ad的提醒下,直接枚举每个集合,开一个单调队列就可以了(然后就卡过去了,这评测姬真是傲娇)
#include <cstdio>
#include <cstring>
using namespace std;
int n, Q, A[310], B[310], f[310][10010], q[10010], hd, tl;
int MAX(int A, int B) { return A>B?A:B; }
int main() {
int T; scanf("%d", &T);
while(T --) {
// memset(f, 0, sizeof(f));
scanf("%d%d", &n, &Q);
for(int i = 1 ; i <= n ; ++ i) scanf("%d%d", &A[i], &B[i]);
for(int i = 1 ; i <= n ; ++ i) {
if(A[i]>10000) continue;
for(int j = 0 ; j < A[i] ; ++ j) {
f[i][j] = f[i-1][j];
hd = tl = 0, q[tl ++] = j;
for(int k = j+A[i] ; k <= 10000 ; k += A[i]) {
while(hd<tl&&(k-q[hd])/A[i]>B[i]) ++ hd;
f[i][k] = MAX(f[i-1][k], f[i-1][q[hd]]+k-q[hd]);
while(hd<tl&&f[i-1][q[tl-1]]-q[tl-1]<f[i-1][k]-k) -- tl;
q[tl ++] = k;
}
}
}
for(int i = 1 ; i <= n ; ++ i) {
for(int j = 1 ; j <= 10000 ; ++ j) f[i][j] += f[i][j-1];
}
for(int i = 1, l, r, m ; i <= Q ; ++ i) {
scanf("%d%d%d", &l, &r, &m);
printf("%d\n", f[m][r]-f[m][l-1]);
}
}
// while(1);
return 0;
}
T2 电磁领域
- 这是道博弈论的题,考场上表示无限懵逼,YY了这个东西很久,推出了一个看似很有用实际是错的的结论
- 其实就是求每个点的sg值然后异或起来,并不知道为什么每个点是独立的QAQ
#define MAXN 20010UL
#include <queue>
#include <cstdio>
#include <cstring>
using namespace std;
int n, m, t, K, f[MAXN], d[MAXN], dis[MAXN];
bool ins[MAXN];
queue <int> q;
struct Edge { int hou, nt, zhi; } sg[MAXN*5];
void Add(int x, int y, int z) {
sg[t] = (Edge){y, d[x], z}, d[x] = t ++;
sg[t] = (Edge){x, d[y], z}, d[y] = t ++;
return;
}
void Spfa(int x) {
memset(dis, 0x3f, sizeof(dis));
dis[x] = 0, q.push(x);
while(!q.empty()) {
int op = q.front();
q.pop();
ins[op] = false;
for(int i = d[op] ; i != -1 ; i = sg[i].nt) {
if(dis[sg[i].hou]>dis[op]+sg[i].zhi) {
dis[sg[i].hou] = dis[op]+sg[i].zhi;
if(!ins[sg[i].hou]) ins[sg[i].hou] = true, q.push(sg[i].hou);
}
}
}
return;
}
int Dp(int x) {
if(f[x]!=-1) return f[x];
bool rel[110] = {0};
int ch = 0;
for(int i = d[x] ; i != -1 ; i = sg[i].nt) if(dis[sg[i].hou]>dis[x]) {
++ ch;
rel[Dp(sg[i].hou)] = true;
}
if(ch==0) f[x] = 1;
else {
for(int i = 0 ; ; ++ i) if(!rel[i]) {
f[x] = i;
break;
}
}
// printf("f[%d] = %d\n", x, f[x]);
return f[x];
}
int main() {
int x, y, z;
while(~scanf("%d%d%d", &n, &m, &K)) {
t = 0, memset(d, -1, sizeof(d));
for(int i = 1 ; i <= m ; ++ i) scanf("%d%d%d", &x, &y, &z), Add(x, y, z);
Spfa(1);
memset(f, -1, sizeof(f));
int ans = 0;
for(int i = 1 ; i <= K ; ++ i) scanf("%d", &x), ans ^= Dp(x);
puts(ans?"QQ":"Other");
}
// while(1);
return 0;
}
T3 觉醒力量
- 看完题后一脸懵逼, 那个提示似乎并没有什么卵用, 我看到之后竟然条件反射地以为前面那个数(实际应该是后面那个)不是个质数(QWQ)
- 我们把第二个模数分解后发现它就是11, 13, 17, 19的乘积, 然后对每个数分别维护一颗线段树,第二个答案直接CRT合并
#define MAXN 100010UL
#include <cstdio>
#include <cstring>
#define MOD 46189
using namespace std;
int n, m, inv_11, inv_13, inv_17, inv_19, w[MAXN], bg[MAXN], Ans[4];
char s[20][20] = {"Fight", "Flying", "Poison", "Ground", "Rock", "Bug", "Ghost", "Steel", "Fire", "Water", "Grass", "Electric", "Psychic", "Ice", "Dragon", "Dark", "Fairy"};
char c[20];
int Ksm(int x, int k, int mod) {
x %= mod; int ret = 1;
while(k) {
if(k&1) ret = ret*x%mod;
x = x*x%mod;
k >>= 1;
}
return ret;
}
struct Seg_ment {
int Mod, bn[MAXN<<2][22];
void Build(int i, int l, int r) {
if(l==r) {
for(int j = 0 ; j < Mod ; ++ j) {
if(bg[l]==1) bn[i][j] = (j+(w[l]%Mod))%Mod;
else if(bg[l]==2) bn[i][j] = (j+Mod-(w[l]%Mod))%Mod;
else if(bg[l]==3) bn[i][j] = 1ll*j*(w[l]%Mod)%Mod;
else if(bg[l]==4) bn[i][j] = Ksm(j, w[l]%(Mod-1), Mod);
}
return;
}
int mid = (l+r)>>1;
Build(i<<1, l, mid), Build(i<<1|1, mid+1, r);
for(int j = 0 ; j < Mod ; ++ j) {
bn[i][j] = bn[i<<1|1][bn[i<<1][j]];
}
return;
}
void Modify(int i, int l, int r, int pos) {
if(l==r) {
for(int j = 0 ; j < Mod ; ++ j) {
if(bg[l]==1) bn[i][j] = (j+w[l]%Mod)%Mod;
else if(bg[l]==2) bn[i][j] = (j+Mod-(w[l]%Mod))%Mod;
else if(bg[l]==3) bn[i][j] = 1ll*j*(w[l]%Mod)%Mod;
else if(bg[l]==4) bn[i][j] = Ksm(j, w[l]%(Mod-1), Mod);
}
return;
}
int mid = (l+r)>>1;
if(pos<=mid) Modify(i<<1, l, mid, pos);
else Modify(i<<1|1, mid+1, r, pos);
for(int j = 0 ; j < Mod ; ++ j) {
bn[i][j] = bn[i<<1|1][bn[i<<1][j]];
}
return;
}
}T[4];
void Solve(int x) {
int ans = 0;
for(int i = 0 ; i < 4 ; ++ i) Ans[i] = T[i].bn[1][x%T[i].Mod];
ans = ((Ans[0]*inv_11%MOD)+(Ans[1]*inv_13%MOD)+(Ans[2]*inv_17%MOD)+(Ans[3]*inv_19%MOD))%MOD;
// printf("ans = %d\n", ans);
printf("%s %d\n", s[Ans[2]], ans);
return;
}
int Cal(char str) {
if(str=='+') return 1;
if(str=='-') return 2;
if(str=='*') return 3;
if(str=='^') return 4;
}
int main() {
// freopen("hidpower.in", "r", stdin);
// freopen("hidpower.out", "w", stdout);
inv_11 = 1ll*Ksm(MOD/11, 9, 11)*(MOD/11)%MOD;
// printf("inv_11 = %d\n", inv_11);
inv_13 = Ksm(MOD/13, 11, 13)*(MOD/13)%MOD;
inv_17 = Ksm(MOD/17, 15, 17)*(MOD/17)%MOD;
inv_19 = Ksm(MOD/19, 17, 19)*(MOD/19)%MOD;
scanf("%d%d", &n, &m);
for(int i = 1 ; i <= n ; ++ i) {
scanf("%s", c);
bg[i] = Cal(*c);
int len = strlen(c);
for(int j = 1 ; j < len ; ++ j) w[i] = w[i]*10+c[j]-'0';
}
T[0].Mod = 11, T[1].Mod = 13, T[2].Mod = 17, T[3].Mod = 19;
for(int i = 0 ; i <= 3 ; ++ i) T[i].Build(1, 1, n);
for(int i = 1, op, x ; i <= m ; ++ i) {
scanf("%d%d", &op, &x);
if(op==1) Solve(x);
else {
scanf("%s", c);
int opt = Cal(*c), len = strlen(c), num = 0;
for(int j = 1 ; j < len ; ++ j) num = num*10+c[j]-'0';
bg[x] = opt, w[x] = num;
for(int j = 0 ; j <= 3 ; ++ j) T[j].Modify(1, 1, n, x);
}
}
// while(1);
return 0;
}
-
突然发现以前的考试修改都没有写总结,来补一下
-
T1进行分组的时候并没有对内存的问题在进一步考虑,并且最近一直没有什么状态
-
T2并不会博弈这是很大的弱区
-
T3我把模数分解后看到因子那么小竟然没有反应到用线段树直接暴力维护,好像内心一直对CRT有抵制的样子
-
这样下去是要把自己埋了的节奏(QAQTQWQ)
-