6.15 考试修改+总结

昨天考崩了QAQ

几乎写全了暴力分,然而并没有什么卵用

因为只要A掉一道题就比我分高了,比我分高的也至少A掉了一道题QAQ

感觉到一丝淡淡的忧桑

貌似THUSC最后听讲课的那些人几乎都A了两题

看来我的THUSC果然只是RP好啊

第一题

显然选色数最少的颜色,设颜色数为m

考虑存在某个点的方案数,设这个点到k距离i个点

则方案数为(n-1-i)!/ ((m-i)!*j!*k!……) j,k等是其他颜色的色数

总方案也是非常好算的,这样我们就可以计算每个点对于期望的贡献了

这样做是O(n^2)的

之后我们考虑t=1的暴力分

不难发现问题转化为维护等差数列的和

这是个分块的经典问题,当公差d>sqrt(n)的时候,暴力是sqrt(n)的

当d<sqrt(n)的时候我们可以预处理答案,每个修改的时候暴力把sqrt(n)个d都修改一遍

时间复杂度是O(n*sqrt(n))的

考试的时候只想到了这些,于是就只有50分

之后我们注意到当t>1的时候,m<=n/2

则一个点到k的距离每多一个点,概率至少/2

不难发现当我们距离很大的时候,概率很小对于本题的精度要求不会有影响,这样我们就不用计算了

然后t=1我们维护分块,t>1的时候我们暴力左右50-100个计算答案就可以了

QAQ 悲桑的事情是考后改题我就只给我的程序加了一句话,然后就A了 QAQ

总结一下为什么没有看出来每次概率要/2这件事情

因为我算的时候不是滚动过去算概率的QAQ我是取ln之后exp回去的

所以什么也看不出来

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std;

const int oo=0x7fffffff;
const int maxn=100010;
int n,m,x,y,type,mn,blo;
int t,k,d,c[maxn];
int val[maxn];
int S[330][330];
long double jc[maxn];

void Get_pre(){
    for(int i=1;i<=blo;++i){//步长
        for(int j=1;j<=i;++j){
            for(int k=j;k<=n;k+=i){
                S[i][j]=S[i][j]+val[k];
            }
        }
    }
    return;
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)scanf("%d",&val[i]);
    jc[0]=0;
    for(int i=1;i<=n;++i)jc[i]=jc[i-1]+log(i);
    blo=(int)(sqrt(n));
    Get_pre();
    while(m--){
        scanf("%d",&type);
        if(type==1){
            scanf("%d%d",&x,&y);
            int v=y-val[x];
            val[x]=y;
            for(int i=1;i<=blo;++i){
                int Q=(x-1)%i+1;
                S[i][Q]+=v;
            }
        }else{
            scanf("%d%d%d",&t,&k,&d);
            for(int i=1;i<=t;++i)scanf("%d",&c[i]);
            if(t==1){
                int ans=0;
                if(d>blo){
                    ans=val[k];
                    for(int i=k+d;i<=n;i+=d)ans+=val[i];
                    for(int i=k-d;i>=1;i-=d)ans+=val[i];
                }else{
                    int Q=(k-1)%d+1;
                    ans=S[d][Q];
                }printf("%d",ans);
                printf(".0000\n");
            }else{
                mn=oo;long double P=0;
                long double ans=0;
                for(int i=1;i<=t;++i){
                    mn=min(mn,c[i]);
                    P=P-jc[c[i]];
                }
                long double sum=P+jc[n-1];
                int cnt=0;P=P+jc[mn];
                for(int i=k+d;i<=n;i+=d){
                    cnt++;
                    if(cnt>100)break;
                    if(cnt>mn)break;
                    long double tmp=P-jc[mn-cnt]+jc[n-1-cnt]-sum;
                    ans=ans+exp(tmp)*val[i];
                }cnt=0;
                for(int i=k-d;i>=1;i-=d){
                    cnt++;
                    if(cnt>100)break;
                    if(cnt>mn)break;
                    long double tmp=P-jc[mn-cnt]+jc[n-1-cnt]-sum;
                    ans=ans+exp(tmp)*val[i];
                }ans=ans+val[k];
                printf("%.4lf\n",(double)(ans));
            }
        }
    }return 0;
}

第二题

首先k=0是普及组的题目

k=1的时候求直径就可以了

k=n,c=1的时候问题中转换成了把这个树分割成最少的链

然后我就开始dp了,最后35分滚粗

考后跟lyc交流了一下发现我的dp做法只要加k一维多做个树上背包就能A了QAQ

我们知道k=n的时候是分割最少链

那么实际上这道题求的是把树分割成k条互不相交的链使得链上的边权和最大

不难发现这个问题具有可以dp的性质,做树上背包就可以了

转移的时候分类讨论一下QAQ

时间复杂度的分析同HAOI2015的那道一样,是O(nk)的QAQ

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;

const int maxn=10010;
const int oo=0x7fffffff/3;
int n,K,c;
int u,v,w,ans;
int h[maxn],cnt=0;
int sz[maxn];
int f[2010][2010][2];
int tmp[2010][2];
struct edge{
    int to,next,w;
}G[maxn<<1];

void add(int x,int y,int z){
    ++cnt;G[cnt].to=y;G[cnt].next=h[x];G[cnt].w=z;h[x]=cnt;
}
void read(int &num){
    num=0;char ch=getchar();
    while(ch<‘!‘)ch=getchar();
    while(ch>=‘0‘&&ch<=‘9‘)num=num*10+ch-‘0‘,ch=getchar();
}
void DP(int u,int fa){
    sz[u]=1;f[u][0][0]=0;f[u][1][1]=-c;
    for(int k=h[u];k;k=G[k].next){
        int v=G[k].to;
        if(v==fa)continue;
        DP(v,u);
        for(int i=0;i<=sz[u]+sz[v];++i)tmp[i][0]=tmp[i][1]=-oo;
        for(int i=0;i<=sz[u];++i){
            for(int j=0;j<=sz[v];++j){
                int now=i+j;

                tmp[now][0]=max(tmp[now][0],f[u][i][0]+f[v][j][0]);
                if(now>=1)tmp[now-1][0]=max(tmp[now-1][0],f[u][i][1]+f[v][j][1]+G[k].w+c);

                tmp[now][1]=max(tmp[now][1],f[u][i][0]+f[v][j][1]+G[k].w);
                tmp[now][1]=max(tmp[now][1],f[u][i][1]+f[v][j][0]);

            }
        }sz[u]+=sz[v];
        for(int i=0;i<=sz[u];++i){
            f[u][i][0]=max(f[u][i][0],tmp[i][0]);
            f[u][i][1]=max(f[u][i][1],tmp[i][1]);
        }
    }
    return;
}

int main(){
    while(scanf("%d%d%d",&n,&K,&c)==3){
        memset(h,0,sizeof(h));cnt=0;ans=0;
        for(int i=1;i<n;++i){
            read(u);read(v);read(w);
            u++;v++;
            add(u,v,w);add(v,u,w);
            ans+=w;
        }
        memset(f,-0x3f,sizeof(f));
        DP(1,-1);ans<<=1;
        int S=0;
        for(int i=0;i<=K;++i){
            S=max(S,f[1][i][0]);
            S=max(S,f[1][i][1]);
        }ans-=S;
        printf("%d\n",ans);
    }return 0;
}

第三题

好神的题目!花了半天才弄懂

首先我们注意到如果我们给每个字母随机值之后计算行列式

不难发现如果行列式在模2意义下不为0,则一定是No,否则可能是Yes,也可能是No

然后某个奇怪的定理指出在域F下随机带入并计算行列式,行列式为0的概率是d/F

F是域的大小,这样我们只需要找到一个足够大的域F就可以了

显然不能是模2剩余系,因为大小为2

不妨构造一个系数均为0或1的k次多项式,我们让他对一个不可约多项式M取模,构成多项式环

域的大小显然是2^k

这样我们给每个字母随机一个多项式并计算行列式就可以了

由于是在模2意义下进行,所以多项式的运算可以采用位运算加速

设多项式f,g

则f-g=f+g=f^g

对于f*g我们可以采取类似快速乘的方式分解掉g并分别与f相乘

计算行列式的时候由于我们只关注是否为0,所以把除法转换成乘法

至于对M取模,即f=min(f,f-M)

即f=min(f,f^M)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int M=0x20000035;

const int maxn=52;
int T,n;
int val[1010];
int A[maxn][maxn];
char s[maxn][maxn][112];

void read(char *s){
    char c;
    while(c=getchar(),c!=‘+‘&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘));
    *(s++)=c;
    while(c=getchar(),c==‘+‘||(c>=‘a‘&&c<=‘z‘)||(c>=‘0‘&&c<=‘9‘))*(s++)=c;
    *(s++)=‘+‘;*s=0;
}
int mul(int a,int b){
    int s=0;
    while(b){
        if(b&1)s=s^a;
        a<<=1;a=min(a,a^M);b>>=1;
    }return s;
}
int Get_val(char *s){
    int now=0,t=1,len=strlen(s);
    for(int i=0;i<len;++i){
        if(s[i]==‘+‘)now^=t,t=1;
        else if(s[i]>=‘a‘&&s[i]<=‘z‘)t=mul(t,val[s[i]]);
        else t=s[i]-‘0‘;
    }return now;
}
bool Gauss(){
    for(int i=1;i<=n;++i){
        int k=0,to;
        for(to=i;to<=n;++to)if(A[to][i])break;
        if(to>n)return 1;
        if(to!=i)for(int j=1;j<=n;++j)swap(A[i][j],A[to][j]);
        for(int j=i+1;j<=n;++j){
            if(A[j][i]){
                int x=A[i][i],y=A[j][i];
                for(int k=i;k<=n;++k){
                    A[j][k]=mul(A[j][k],x)^mul(A[i][k],y);
                }
            }
        }
    }return 0;
}
bool judge(){
    for(int i=‘a‘;i<=‘z‘;++i)val[i]=rand();
    for(int i=1;i<=n;++i){
        for(int j=1;j<=n;++j){
            A[i][j]=Get_val(s[i][j]);
        }
    }return Gauss();
}

int main(){
    srand(809495818);
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)read(s[i][j]);
        bool flag=true;
        for(int T=10;T&&(flag=judge());T--);
        if(flag)printf("Yes\n");
        else printf("No\n");
    }return 0;
}

考试的时候失误很大

首先第一题非常接近正解,然而没有注意到t>1的时候概率递减的非常快(因为我取得log之后exp回去的)

所以没有A掉

至于第二题已经成功把问题转化成分割链的问题了,而且知道了k没有限制时的DP做法

但是考试的时候没有继续思考,从而没有发现只要在加一维表示k就可以同样做DP了

第三题嘛QAQ

时间: 2024-07-28 17:36:00

6.15 考试修改+总结的相关文章

5.28 考试修改+总结

今天又是一个悲伤的故事,所有排名比我高的人第一题都A了 而我第一题爆零了 但是开心的事情是:第一题没有说是简单图,所以题解是错的 不管怎么样,将错就错吧 今天下午断网了,所以这时候才写blog 第一题 由于题目中没有给出欧拉图的概念,所以我完全不知道它在说啥,于是就爆零了 然后欧拉图就是存在欧拉回路的简单图,具有以下特点: 1.联通 2.度数都是偶数 显然我们将错就错看题目的话,把欧拉图数目*(n*(n-1)/2+1)就可以得到答案了 然后我们很容易知道度数均为偶数的图的数目是2^((n-1)*

5.26 考试修改+总结

论写5K+的代码在只有样例的条件下都可以调对 由此可见,勇气才是成功的关键 先放题解吧 第一题上午写的暴力不小心忘记题目换根之后还会染色了 然后就挂成了5分QAQ 有很大的部分分是SDOI染色,还有一部分是旅行 但是考试犯懒没有写 很容易发现任何一种颜色在树上都是连续的一段 那么我们不妨这么定义,如果一条边两端颜色不相同,我们定义为虚边,会对子树每个答案产生+1的贡献 如果两端颜色相同,我们定义为实边,不会产生贡献 不难发现,这样定义后的实边和虚边的性质和LCT的定义是一样的 我们考虑使用LCT

15、修改sqldeveloper的JDK路径

15.1.说明: 1.第一次使用Oracle SQL Developer时会提示选择JDK路径(只会在第一次使用时提示), 如果选择了高版本的JDK(1.8)路径,可能会出现了如下两种情况: (1)sqldeveloper出现闪退的问题,无法进入Oracle SQL Developer. (2)sqldeveloper无法选择utf8字符集. 15.2.解决办法: 1.找到sqldeveloper安装路径下的"sqldeveloper\bin\sqldeveloper.conf"文件.

6.3 考试修改+总结

今天下午考试被FFT和数论题目翔了一脸QAQ 做的是Newscafe杯的题目 第一题 异化多肽 显然构造多项式f 答案是f+f^2+f^3…… 化简一下得1/(1-f) 之后多项式求逆即可 考试的时候推了好久的多项式求逆的式子(感觉自己什么都忘光了 #include<cstdio> #include<cstring> #include<iostream> #include<cstdlib> #include<algorithm> #define

6.11 考试修改+总结

第三题至今没敢写,感觉好恐怖QAQ 今天考得好糟糕 第一题只写了10分的暴力+(k=1)20分的网络流 后来题解告诉我k>1的时候可以分治到k=1,每层分治解决方法是同k=1的 考试的时候没有注意到2^k这个比较神奇的可以分治的性质 而且自己考场上丝薄了,没有发现因为是二分图可以直接跑欧拉回路的性质,而是裸套网络流模型 第二题其实已经接近想出了题解 自己考试的时候成功证明了暴力的复杂度是线性的 但是没有想到如何寻找0-1对,然后就只能暴力用Splay维护1所在的位置了 默默祈祷数据不要太卡我的做

6.10 考试修改+总结+颓废记

昨天晚上得到了非常不爽的消息,zcg要去给高一讲课,而我并不能去 虽然什么事情并不能都顺着我的心意来吧,但是这件事情真是让人越想越不痛快 要知道,我从去年就一直期待着给高一讲课呢 所以今天考试非常不开心,一般这个时候我会选择爆零的 但是想了想觉得爆零太难看,就看了看好像第一题可做 在教学楼里颓废了好久然后吃了点东西,用最后的时间码完了第一题 (反正二.三题我没看出来怎么做,所以暴力也不想写了 然后惊讶的是,只有第一题程序的窝rank1了QAQ 先放题解吧 第一题: 首先我们注意到转置的实质是某个

5.27 考试修改+总结

这是一个悲伤的故事 上午写manacher的时候往里面加#号,然后统计有效字符的个数 然后我就开始模拟,一个长度为6的串我都能数错有多少个有效字符 我把2个字符数成了3个!然后暴力就挂掉了5分.. 为什么这几天的暴力总是会挂掉,真是奇怪(看来是最近自己内心不太稳了 (大概是被那个梦吓得吧QAQ) 今天又A了两道题目,感觉天天都是两道正解+挂掉的暴力QAQ 先放题解吧 第一题是之前数位DP坑掉的题目,然后今天尝试着写了写,感觉不是很难 但是并不是用数位DP做的 先考虑加密的情况,我们只需要统计每一

6.19 考试修改+总结

QAQ 又是一套水题集合 然后忧伤的故事是老师把时间调到了四个小时半 我又因为想要出道题花了半个小时写了一些其他的东西 然后最后没有写完题!QAQ 不然第三题可能多拿点分 上午的时候把所有题目的正解都想了出来 唯一美中不足的是自己想的第三题是O(n^4*300)的是时间复杂度 实际上离散化区间之后只会有n个区间,时间复杂度就是O(n^5)了QAQ 先说题解把 第一题 决战圆锥曲线 显然给定你的那个函数a*x+b*y+c*x*y对于x,y是相对等价的 又因为题目的输入具有随机性,显然可以通过维护线

2017.8.15 考试

注:所有题目的时间限制均为 1s ,内存限制均为 256MB . 1 1 .第K K 小数( ( number .cpp/c/pas)[问题描述]有两个正整数数列,元素个数分别为N和M.从两个数列中分别任取一个数相乘,这样一共可以得到N*M个数,询问这N*M个数中第K小数是多少.[输入格式]输入文件名为number.in.输入文件包含三行.第一行为三个正整数N,M和K.第二行为N个正整数,表示第一个数列.第三行为M个正整数,表述第二个数列.[输出格式]输出文件名为number.out.输出文件包