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

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

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我不会, 这个坑有空再填吧…

最后的最后,

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值