【学术篇】辣鸡出题人吃枣药丸!!!!

来源:互联网 发布:dcm方向余弦矩阵 编辑:程序博客网 时间:2024/04/29 00:16

辣鸡出题人吃枣药丸!!!!

2017.11.01 这是一次取得了圆满失败的胡策…..

T1(set): 给你n个数, 求出一个非空子集, 使这个集合元素之和为n的倍数.
本题做法:
算法0: 输出-1.
时间复杂度O(1) 空间复杂度O(1) 期望得分10 实际得分0.
算法1: 容易发现, 当其中有数字%n==0时, 输出这个数即可.
时间复杂度O(n) 空间复杂度O(1) 期望得分10 实际得分50.
算法2: 对于20%的数据, n<=20
枚举每个集合判断即可…
时间复杂度O(2n) 空间复杂度O(n) 期望得分20 实际得分20. 结合算法1, 得分50.
算法3: 对于50%的数据, n<=1000
dp 设f[i][j]为前i个数的和%n等于j的情况是否存在, 状态转移方程如下:

f[0][0]=1;f[i][(j+a[i])%n]=f[i-1][j];f[i][j]=f[i-1][j]; (i!=1&&j!=0)

时间复杂度O(n2) 空间复杂度O(n2) 期望得分50 实际得分60. 结合算法1, 得分60.
算法4(正解): n<=1000000 鸽巢原理(其实对于OI来说这个原理只有这一个题)
考虑前缀和, 有n个取值, 而对于n的剩余系, 有1~n-1这些取值, 所以至少有两个是相同的, 把他们中间的输出即可.
时间复杂度O(n) 空间复杂度O(n) 期望得分100 实际得分100.
代码:

 #include <cstdio>int a[1000010],b[1000010];inline int gn(){    int a=0;char c=getchar();for(;c<'0'||c>'9' ;c=getchar());    for(;c>47&&c<58;c=getchar()) a=(a<<1)+(a<<3)+c-48; return a;}int main(){    freopen("set.in","r",stdin); freopen("set.out","w",stdout);    int n=gn(),s=0; for(int i=1;i<=n;i++) a[i]=gn()%n;    for(int i=1;i<=n;i++){        s=(s+a[i])%n;        if(b[s]){ printf("%d\n",i-b[s]);            for(int j=b[s]+1;j<=i;++j) printf("%d ",j); return 0;         }else b[s]=i;    }}

算法5(“正解”): 什么都不输出…
时间复杂度O(0) 空间复杂度O(0) 期望得分0 实际得分100.
这是本题时空复杂度最优的解法, 码长也是最短的, 而出题人并没有想到这种做法…
算法解释:
fscanf等函数对于读入失败的返回值是EOF而不是0
所以判断的时候要用~而不是!
辣鸡出题人水平菜还写spj
结果TM不输出都能AC啊
不过终于有一道比NOIP D1T1还简单的题了
总之辣鸡出题人吃枣药丸
下面贴代码:

#include<cstdio>main(){freopen("set.out","w",stdout);}

算法注意事项: 一定要写输出文件, 不然会报”文件错误”…
这题就这么着吧…

辣鸡出题人吃枣药丸!!!!

T2: 给一个A数组, 求将这个数组排列成两两不相同, 至少要去掉多少元素.
而A数组的给出方式是这样的:

//第一行读入两个个整数 M, K.//接下来一行读入 M 个整数 count[i], 其中 N=∑count[i] .//接下来一行读入 M 个整数 X[i].//接下来一行读入 M 个整数 Y[i].//接下来一行读入 M 个整数 Z[i].int N = 0, S = (1 << K) - 1;for (int i = 1; i <= M; ++i) {    N = N + 1;    A[N] = X[i];    long long last = X[i];    for (int j = 1; j < count[i]; ++j) {        last = (last * Y[i] + Z[i]) & S;        N = N + 1;        A[N] = last;    }}//辣鸡出题人还"贴心"的加了一句:"注意:因为生成 A[i]的方法不好用语言描述, 所以用代码来表达. 直接照搬代码的话后果自负.Emmmm..."

时限1s 空间16MB(够开4M int数组)

本题做法:
算法1: 什么都不输出…
时间复杂度O(0) 空间复杂度O(0) 期望得分100 实际得分0. (因为本题并没有spj…)
好的, 我们容易看出:
我们找出出现次数最多的一个数x
排成这样:x,a,x,b,x,c,x,…,x (a,b,c等是不等于x的数,他们可以相等
这样很显然答案就是x2n1
当然如果是负数就该输出0了
算法2: subtask#1 10pts N<=20
想怎么做怎么做.. 就是这么为所欲为..
时间复杂度O(为所) 空间复杂度(欲为) 期望得分10 实际得分10.
算法3: subtask#2 20pts N<=1000000
这个是能存下来的.. 随便搞搞就出来了…
时间复杂度O(n)~O(nlogn) 空间复杂度O(n) 期望得分30 实际得分30.
算法4: subtask#3 20pts K<=20
这个可以开桶… 好像比上面的还要好做…
时间复杂度O(2^K) 空间复杂度O(2^K) 期望得分30 实际得分30 结合算法3, 得分50.
算法5(正解): subtask#4 50pts N<=50000000 K<=30
50000000…一看就是O(n)嘛… 两遍O(n)好像都过不了吧, 辣鸡出题人都丧心病狂的卡内存了, 卡个常数很正常吧…(flag√)
但是好像有一道题可以4MB找众数来着28…(然而我并找不到链接了…)
听dalao说, bzoj有一道mode的题也是这么个东西..(然而辣鸡bzoj 502 Bad Gateway了)
就是 存两个变量p q
开始时p=-1(随便找个不可能取到的值), q=1
然后扫, 访问到i, 如果i==p q++ 否则q– 如果q==0 则用i替换p,q恢复为1
这样就可以找到出现次数最多且次数大于n2的数了
然后再扫一遍找出它的出现次数即可…
喂!!!为什么这样能过啊!!!
Emmmm反正最后就是过了…也就是这么暴力….
代码:

#include <cstdio>int x[1004],y[1005],z[1006],w[1007];inline int gn(){    int a=0;char c=getchar();for(;c<'0'||c>'9' ;c=getchar());    for(;c>47&&c<58;c=getchar()) a=(a<<1)+(a<<3)+c-48; return a;}int main(){    freopen("read.in","r",stdin); freopen("read.out","w",stdout);    int m=gn(),k=gn(),s=(1<<k)-1,p=-1,q=1,n=0;    for(int i=1;i<=m;++i) w[i]=gn();for(int i=1;i<=m;i++) x[i]=gn();    for(int i=1;i<=m;++i) y[i]=gn();for(int i=1;i<=m;i++) z[i]=gn();    for(int i=1;i<=m;++i){        if(x[i]==p) q++; else {q--; if(!q) p=x[i],q=1;}        long long last=x[i]; ++n;        for(int j=1;j<w[i];++j){            last=(last*y[i]+z[i])&s; ++n;            if(last==p) q++; else {q--; if(!q) p=last,q=1;}        }    } q=0;    for(int i=1;i<=m;++i){        if(x[i]==p) q++; long long last=x[i];        for(int j=1;j<w[i];++j){            last=(last*y[i]+z[i])&s;            if(last==p) q++;        } //这两遍明明就是抄的...    } if((q=q*2-n-1)>0) printf("%d",q); else putchar(48);}

就这样吧…

T3我不会, 这个坑有空再填吧…

最后的最后,

——辣鸡出题人吃枣药丸!!!!