[UOJ267]【清华集训2016】魔法小程序
有这样一段魔法的程序:(其中所有的数组下标从 0 0 开始,所有的除法的结果为整数,且向 取整)
定义数组 a[], b[], c[]
定义函数 魔法(x, y, z):
{
如果 a 的长度 == z:
返回 x >= y
如果 x % a[z] < y % a[z]:
返回 假
返回 魔法(x / a[z], y / a[z], z + 1)
}
定义函数 主程序():
{
读入 a[], b[]
令 c[] 的长度与 b[] 的长度相同,且 c[] 的每个元素均为 0
令 变量 i 从 0 循环至 b 的长度 - 1:
令 变量 j 从 0 循环至 i:
如果 魔法(i, j, 0):
c[i] += b[j]
输出 a[], c[]
}
这个程序目前十分低效(显然时间复杂度至少是平方量级的),无法快速完成百万级别的计算,但我们现在的任务不仅是优化它。
现在我们给出这段程序的输出,你需要完成一个“非确定机”的工作,给出一个可能的输入。
请注意本题的空间限制。
输入格式
第一行输入 a a 的长度。第二行输入一些空格隔开的正整数,依次表示 的每一项。
第三行输入 c c 的长度。第四行输入一些空格隔开的整数,依次表示 的每一项。
每一行相邻的两个数,恰好用一个空格隔开。
a a 的长度不会超过 。 a a 的每一个元素不会超过 。
c c 的长度不会超过 。对 c c 的元素的范围没有直接的保证,但是保证存在一个解 ,使得 b b 的每一个元素的绝对值都不超过 。
a a 和 都至少拥有一个元素。
输出格式
第一行输出 a a 的长度。第二行输入一些空格隔开的正整数,依次表示 的每一项。
第三行输出 b b 的长度。第四行输入一些空格隔开的整数,依次表示 的每一项。
每一行相邻的两个数,恰好用一个空格隔开。
你必须保证你输出的 b b 的每一个元素的绝对值都不超过 。保证存在一个可行的解满足这个条件。如果有多个可行的解,你可以输出任意一个。
样例一
input
3 2 3 3 10 1 0 2 9 3 8 4 7 5 6
output
3 2 3 3 10 1 -1 1 8 1 -2 3 4 0 -10
限制与约定
本题分为若干个子任务,但是不采用捆绑测试。每个子任务中有若干个测试点,只要你对于某个测试点的输出正确,即可获得该测试点的分数。某个子任务的分数是指其各个测试点的分数之和。
我们设 n n 为 的长度,设 m m 为 的长度,则:
子任务 1(4分)
n=1 n = 1 , m≤100 m ≤ 100 。
子任务 2(22分)
n≤100 n ≤ 100 , m≤100 m ≤ 100 。
子任务 3(6分)
n≤1000 n ≤ 1000 , m≤1000 m ≤ 1000 。
子任务 4(8分)
n≤104 n ≤ 10 4 。
子任务 5(21分)
n=2m n = 2 m , a a 中所有元素均为 。
子任务 6(9分)
a a 中所有元素均为 。
子任务 7(7分)
m=1 m = 1 。
子任务 8(12分)
m≤20 m ≤ 20 。
子任务 9(11分)
没有特殊的约定。
时间限制: 1s 1 s
空间限制: 32MB 32 MB
下载
分析&&思路:
通过分析这段代码,我们可以很快的知道,这个程序其实就是实现一个多维前缀和的问题,a数组记录每一维有多长,c数组记录的就是前缀和。那么我们考虑一下前缀和的方式,用前缀和的逆操作,即可还原出原数组。显然大于1的维数不会超过 log(m) l o g ( m ) ,所以我们只要暴力就行了。
Code
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
const int maxn=1000005;
ll n,m,a[maxn],sum[maxn],tp[maxn],c[maxn],len;
int main() {
read(n);
printf("%lld\n",n);
for(int i=0,x;i<n;i++) {
read(x);
printf("%d%c",x,i==n-1?'\n':' ');
tp[++len]=x;
if(x==1) {
n--,i--;
continue;
}
else
a[i]=x;
}
read(m);
a[n++]=0x3f3f3f3f;
for(int i=0;i<m;i++)
read(c[i]);
sum[0]=1;
for(int i=1;i<n;i++) {
sum[i]=a[i-1]*sum[i-1];
if(sum[i]>m) {
n=i;
break;
}
}
for(int j=0;j<n;j++) {
int x=m%sum[j],y=m/sum[j]%a[j];
for(int i=m-1;~i;i--) {
if(x)
x--;
else {
x=sum[j]-1;
y=y?y-1:a[j]-1;
}
if(y)
c[i]-=c[i-sum[j]];
}
}
printf("%lld\n",m);
for(int i=0;i<m;i++)
printf("%lld%c",c[i],i==m-1?'\n':' ');
return 0;
}