题面
我们现在要攻击一个程序。
认为两个数相乘花费的时间为两个数二进制下位数的乘积。
\(x\) 的二进制下位数即 \(\lfloor \log_2 x \rfloor + 1\),特别地 \(0\) 的位数 为 \(1\)。
给定 \(n,mod\),这个程序有五个内置的参数 \(u, v, k, r, q\),运行框架大致如下:
- 输入一个 \(n \times n\) 的矩阵 \(A\)。
- 将 \(A_{u,v}\) 设为 \(k \times \left( \sum\limits_{i=0}^{n-1} \sum\limits_{j=0}^{n-1} A_{i,j} \right) + r\)。
- 用矩阵快速幂的方法求出 \(A^q\),具体实现可以参考样例
grader.cpp。
所有矩阵的运算均在模 \(mod\) 意义下进行。
每次攻击我们可以输入 \(A\),并得到运行程序所花费的时间(即所有乘法运算时间和)。
我们需要在一定次数内的攻击操作中得知 \(u, v, q\)。
由于我们的算力丰富,拥有充分的容错空间,你可以给出不超过 \(500\) 个可能的 \(q\),只要其中有一个是正确的你就会被认为是正确的。
只要你在 \(\color{red}{\le 5\times 10^4}\) 次询问内找出 \(u,v\) 和可能正确的 \(500\) 个 \(q\),就可获得该测试点满分。
-
你可以获取 \(u\),调用时会扣除该测试点原始分数的 \(10\%\)。
-
你可以获取 \(v\),调用时会扣除该测试点原始分数的 \(10\%\)。
-
你可以获取 \(k\),调用时会扣除该测试点原始分数的 \(20\%\)。
-
你可以获取 \(r\),调用时会扣除该测试点原始分数的 \(20\%\)。
-
你可以获取 \(q\),调用时会扣除该测试点原始分数的 \(80\%\)。
单个测试点分数和 \(0\) 取 \(\max\)。
// grader.cpp
namespace grd
{
int cost;
inline int len(int x){return x?__lg(x)+1:1;}
inline LL mul(int x,int y){cost+=len(x)*len(y);return 1ll*x*y;}
inline Matrix merge(const Matrix &x,const Matrix y)
{
Matrix z;memset(z.a,0,sizeof(z.a));
for(int i=0,j,k;i<n;++i)for(j=0;j<n;++j)for(k=0;k<n;++k)
z.a[i][k]=(mul(x.a[i][j],y.a[j][k])+z.a[i][k])%mod;
return z;
}
inline int gc(Matrix A,int u,int v,int k,int r,int q)
{
cost=0;int s=0;
for(int i=0,j;i<n;++i)for(j=0;j<n;++j) s=(1ll*s+A.a[i][j])%mod;
A.a[u][v]=(mul(s,k)+r)%mod;Matrix B;
for(int i=0,j;i<n;++i)for(j=0;j<n;++j) B.a[i][j]=i==j;
for(int i=0;i<31;++i)
{
if(q>>i&1)B=merge(B,A);
A=merge(A,A);
}
return cost;
}
}using grd::gc;
// 花费形如 gc 计算
对于 \(100\%\) 的数据,保证 \(mod\) 是素数,\(0\le u,v<n,1\le k,r,q<mod\)。
| 测试点编号 | \(n=\) | \(mod\) 的范围 |
|---|---|---|
| \(1\) | \(1\) | \(2^7 < mod < 2^8\) |
| \(2\sim 5\) | \(2\) | \(2^{15} < mod < 2^{16}\) |
| \(6\sim10\) | \(2\) | \(2^{30} < mod < 2^{31}\) |

浙公网安备 33010602011771号