【2021夏纪中游记】2021.7.15模拟赛
2021.7.15模拟赛
比赛概括:
\(\mathrm{sum}=40+0+30+0\)
本来可以拿 \(200\),但是因为没审完题。唉。
T1 彩色圆环:
原题,详见 【YBTOJ】【国家集训队】彩色圆环。
T2 折射伤害:
题目大意:
在一个游戏中有n个英雄,初始时每个英雄受到数值为ai的伤害,每个英雄都有一个技能“折射”,即减少自己受到的伤害,并将这部分伤害分摊给其他人。对于每个折射关系,我们用数对(xi,yi,zi)来表示xi将自己受到伤害去掉zi的比例,将这些伤害转移给yi(xi,yi是整数,zi是实数)。
求出经过反复折射后最后每个英雄受到的实际总伤害。
思路:
求出第 \(i\) 个英雄收到的总伤害(包括折射收到的)\(f(i)\),可以发现:
\[f(i)=a_i+\sum_{j\ne i}z_{j,i}f(j)
\]
以此得到增广矩阵:
\[\left[\begin{array}{lcccr|r}
1&-z_{2,1}&-z_{3,1}&\cdots&-z_{n,1}&a_1\\
-z_{1,2}&1&-z_{3,2}&\cdots&-z_{n,2}&a_2\\
-z_{1,3}&-z_{2,3}&1&\cdots&-z_{n,3}&a_3\\
\vdots&\vdots&\cdots&\ddots&\vdots&\vdots\\
\end{array}\right]\]
高斯消元求解后,再乘上反弹出去的比例就行了。
代码:
const int N = 210;
inline ll Read()
{
ll x = 0, f = 1;
char c = getchar();
while (c != '-' && (c < '0' || c > '9')) c = getchar();
if (c == '-') f = -f, c = getchar();
while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
return x * f;
}
int n, m;
double a[N][N], ref[N];
void Gauss()
{
for (int i = 1; i <= n; i++)
{
int mxi = i;
for (int j = i + 1; j <= n; j++)
if(fabs(a[mxi][i]) < fabs(a[j][i])) mxi = j;
swap(a[mxi], a[i]);
double inv = a[i][i];
for (int j = i; j <= n + 1; j++)
a[i][j] /= inv;
for (int j = i + 1; j <= n; j++)
{
double inv = a[j][i];
for (int k = i + 1; k <= n + 1; k++)
a[j][k] -= inv * a[i][k];
}
}
for (int i = n - 1; i; i--)
for (int j = i + 1; j <= n; j++)
a[i][n + 1] -= a[i][j] * a[j][n + 1];
}
int main()
{
n = Read();
for (int i = 1; i <= n; i++)
a[i][i] = 1.0, a[i][n + 1] = Read() * 1.0;
m = Read();
for (int i = 1; i <= m; i++)
{
int x = Read(), y = Read(); double z;
scanf("%lf", &z);
a[y][x] -= z, ref[x] += z;
}
Gauss();
for (int i = 1; i <= n; i++)
printf ("%.6f\n", a[i][n + 1] * (1 - ref[i]));
return 0;
}
T3 鱼跃龙门:
题目大意:
给定 \(n\),找到最小的 \(x\) 使得 \(2n|x(x+1)\)。
正文:
我们知道 \(2n=p_1^{c_1}\times p_2^{c_2}\times\cdots\times p_m^{c_m}\)
找到其中最大的幂 \(p_x^{c_x}\)。在 \([1,2n]\) 内枚举它的倍数然后在相邻数中检测是否 \(2n\) 的其它幂都能被包含。时间复杂度 \(\mathcal{O}(T\sqrt{n}\mathrm{cnt})\),其中 \(\mathrm{cnt}\) 表示 \(2n\) 的质因数个数,理论上说会被卡,但又好像和标算差不多。
代码:
const int N = 1e6 + 10;
inline ll Read()
{
ll x = 0, f = 1;
char c = getchar();
while (c != '-' && (c < '0' || c > '9')) c = getchar();
if (c == '-') f = -f, c = getchar();
while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
return x * f;
}
bool vis[N];
ll pri[N], cnt;
void Prime()
{
for (int i = 2; i <= N - 10; i++)
{
if (!vis[i]) pri[++cnt] = i, vis[i] = 1;
for (int j = 1; j <= cnt && pri[j] * i <= N - 10; j++)
{
vis[pri[j] * i] = 1;
if (!(i % pri[j])) break;
}
}
}
int t;
ll n;
ll a[N][2], tot;
ll qpow(ll a, ll b)
{
ll ans = 1;
for (; b; a = a * a, b >>= 1)
if (b & 1) ans = ans * a;
return ans;
}
int main()
{
Prime();
for (t = Read(); t--; )
{
n = Read(); n *= 2;
ll m = n;
a[tot = 1][0] = 1, a[tot][1] = 1;
for (int i = 1; i <= cnt; i++)
{
if (m % pri[i]) continue;
a[++tot][0] = pri[i];
a[tot][1] = 0;
for (; !(m % pri[i]); m /= pri[i])
a[tot][1]++;
if (m == 1) break;
}
if (m != 1) a[++tot][0] = m, a[tot][1] = 1;
for (ll i = 1, val = qpow(a[tot][0], a[tot][1]); i * val <= n; i++)
{
int flag = 1;
for (int j = 1; j < tot; j++)
{
ll val1 = qpow(a[j][0], a[j][1]);
if ((i * val - 1) % val1 && (i * val) % val1) {flag = 0; break;}
}
if (flag) {printf ("%lld\n", i * val - 1); break;};
flag = 1;
for (int j = 1; j < tot; j++)
{
ll val1 = qpow(a[j][0], a[j][1]);
if ((i * val + 1) % val1 && (i * val) % val1) {flag = 0; break;}
}
if (flag) {printf ("%lld\n", i * val); break;};
}
}
return 0;
}
T4 [GDOI2017]凡喵识图:
题目大意:
正文:
傻逼文字游戏题目描述。哈希搞搞就好了,个人感觉本题考验代码实现能力。
代码:
const int N = 150010;
inline ll Read()
{
ll x = 0, f = 1;
char c = getchar();
while (c != '-' && (c < '0' || c > '9')) c = getchar();
if (c == '-') f = -f, c = getchar();
while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
return x * f;
}
int n;
ll a[N];
int b[5], vis[N];
int nxt[5][N];
map<int, int> hash[5];
int Solve(ll x)
{
int i = 0;
for (; x; x -= x & -x, i++)
if (i > 3) return 4;
return i;
}
int main()
{
freopen("hashing.in", "r", stdin);
freopen("hashing.out", "w", stdout);
n = Read();
for (int i = 1; i <= n; i++)
{
a[i] = Read();
for (int j = 0; j < 4; j++)
b[j] = (a[i] >> j * 16) % (1 << 16);
int ans = 0;
for (int j = 0; j < 4; j++)
{
if (hash[j].find(b[j]) != hash[j].end())
{
nxt[j][i] = hash[j][b[j]];
for (int k = nxt[j][i]; k; k = nxt[j][k])
{
if (vis[k] == i) continue; vis[k] = i;
if (Solve (a[i] ^ a[k]) == 3) ans++;
}
}
hash[j][b[j]] = i;
}
printf ("%d\n", ans);
}
return 0;
}