今天考的内容,怎么说呢,都有这样的一个过程:读题(哎呀这题什么意思)->理解题(哎呀这题怎么这么简单)->看一眼数据范围(哎呀这道题怎么这么毒瘤),今天的题都不是难,是难拿高分,写暴力的思路一下子就出来了,然后默默的看着数据范围舍弃掉想法......
话说11号信息奥赛的就要都来学校集训了,就都能一起来受虐了qwq
T1:李时珍的皮肤衣
这道题是这次考试之中唯一可做的一道题了,我们想象一下,如果最里层的衣服被照到了,那么最外层的衣服一定都已经经历过了若干次的变化,且此时他们都是透明的,且最后一次照射之后最内层的衣服变为透明,其余的都成为了不透光的,而我们从表格中可以看到每一次操作之后就相当于数字的大小减了1,于是操作的次数就是2^n-2^(n-1)+1,即2^(n-1)+1,加一是因为要算上第一天,推出了式子就可以进行计算了,当然直接计算是不可取的,要用矩阵快速幂.
#include<bits/stdc++.h> unsigned long long n; unsigned long long POW(unsigned long long x,unsigned long long cnt){ unsigned long long ans=1; while(cnt){ if(cnt & 1) ans=(ans*x)%n; cnt>>=1; x=(x*x)%n; //printf("%llu %llu ",ans,x); } return ans%n; } int main(){ scanf("%llu",&n); printf("%llu ",(POW(2,n-1)+1)%n); return 0; } //其实并不用开ull,ll即可
T2:马大嘴的废话
这道题在考试的时候不想写暴力,但是想了近一个小时还是没有头绪,只好打了一个暴力拿了60pts,这道题大佬们都用的什么"Hash","AC自动机",这些我都不会,于是用老师讲的tire字典树进行计算,这是一个比较久远的内容了,但是还是有大佬想到了(但想法被另一个大佬封杀了),所以这道题好像考试时并没有人用tire树,对于一个输入的字符串我们依次存原串,去掉第一个字符的串...以此类推,之后考虑处理重复的情况,我们在增加字符串的时候加上一个编号,如果编号重复就不要再增加该串的增加次数了.
#include<bits/stdc++.h> using namespace std; const int N=5e5+100; int tire[N][26],mark[N][26],cnt[N][26]; char str[25]; int n,m,tot; void Insert(int pos,int end,int id){ int now=0; while(pos<end){ int t=str[pos]-'a'; if(!tire[now][t]){ tire[now][t]=++tot; mark[now][t]=id; cnt[now][t]=1; } else{ if(mark[now][t]!=id){ mark[now][t]=id; ++cnt[now][t]; } } now=tire[now][t]; ++pos; } } int search(char *a){ int len=strlen(a); int now=0,ans=0; for(int i=0;i<len;++i){ if(!tire[now][a[i]-'a']) return 0; ans=cnt[now][a[i]-'a']; now=tire[now][a[i]-'a']; } return ans; } int main(){ scanf("%d",&n); for(int i=0;i<n;++i){ scanf(" %s",str); int len=strlen(str); for(int j=0;j<len;++j) Insert(j,len,i); } scanf("%d",&m); while(m--){ scanf(" %s",str); printf("%d ",search(str)); } return 0; }
T3:SSY的队列
emm......这道题现在的正解我还不会写,因为要用到Hash,而我还不会,只能去拿状压的70pts......但是考完试后发现拿70分的人都非常少是怎么回事,状压都写挂了???其实要当状压写的话这道题就没有什么好说的了,和之前做过考过的一道"互不侵犯"神之类似,都是预处理出第一层,之后把最终的状态进行累加,但是状态要改一下,dp[i][j]表示状态为i的最后一个人为j时的答案,有状态转移dp[j|(1<<(i-1))][i]=(dp[j|(1<<(i-1))][i]+dp[j][k]) % M;之后就直接看代码吧.
#include<bits/stdc++.h> using namespace std; typedef long long ll; int Mod,n,a[50]; ll M=1234567891; ll dp[1<<23][31]; int main(){ scanf("%d",&n); if(n==0){ printf("1 "); return 0; } for(int i=1;i<=n;++i) scanf("%d",&a[i]); scanf("%d",&Mod); int ed=(1<<n)-1; for(int i=1;i<=n;++i) dp[1<<(i-1)][i]=1; for(int j=0;j<=ed;++j) for(int i=1;i<=n;++i) for(int k=1;k<=n;++k){ if(i==k) continue; if(!(j & (1<<(k-1)))) continue; if(j & (1<<(i-1))) continue; if(abs(a[k]-a[i])%Mod==0) continue; dp[j|(1<<(i-1))][i]=(dp[j|(1<<(i-1))][i]+dp[j][k]) % M; } ll ans=0; for(int i=1;i<=n;++i) ans=(ans+dp[ed][i])%M; printf("%lld ",ans); return 0; }
T4:清理牛棚
这道题听说要用单调队列优化线性dp?这些统统不会,打一个map的区间dp直接走人(数组开不下只好用mapQAQ),STL果然没让我失望,T了只得了两个点的分......我会向线性dp屈服吗?当然不会,这里安利一个最短路求法,对于每头猪从他开始的天数到结束的那天建一条边权为花费的边,且每个点都向前一个点连一条边权为0的边,这样就相当与去拼一个M到E的方案,从M跑最短路,如果E可以达到,输出答案即可,反之输出-1
#include<bits/stdc++.h> using namespace std; #define int long long const int N=3e6+10; struct Node{ int next,to,dis; }edge[N]; int Head[N],tot; void Add(int x,int y,int z){ edge[++tot].to=y; edge[tot].next=Head[x]; edge[tot].dis=z; Head[x]=tot; } struct Edge{ int dis,id; Edge(int x,int y){ id=x;dis=y; } bool operator < (const Edge &a)const{ return a.dis<dis; } }; int dis[N],vis[N]; priority_queue<Edge>q; void dijkstra(int x){ memset(dis,0x3f,sizeof(dis)); memset(vis,0,sizeof(vis)); dis[x]=0;q.push(Edge(x,0)); while(!q.empty()){ int u=q.top().id;q.pop(); if(vis[u]) continue; vis[u]=true; for(int i=Head[u];i;i=edge[i].next){ int v=edge[i].to; if(dis[v]>dis[u]+edge[i].dis){ dis[v]=dis[u]+edge[i].dis; q.push(Edge(v,dis[v])); } } } } signed main(){ int n,m,e; scanf("%lld%lld%lld",&n,&m,&e); for(int i=1;i<=n;++i){ int x,y,z; scanf("%lld%lld%lld",&x,&y,&z); if(x<m) x=m; if(y>e) y=e; Add(x,y+1,z); } for(int i=m;i<e;++i){ Add(i+1,i,0); } dijkstra(m); if(dis[e+1]==0x3f3f3f3f3f3f3f3f) printf("-1 "); else printf("%lld ",dis[e+1]); return 0; }
然后就是今天的一些练习题啦,没有什么说的,大部分都是一些板子和一些不好调试的题目,但是写出来还是很简单的,这里就不详细说了,
1 #include<bits/stdc++.h> 2 using namespace std; 3 int agree[505][505][55],dp[505][505][55]; 4 int zhuan(char c){ 5 if(c=='W') return 1; 6 if(c=='I') return 2; 7 if(c=='N') return 3; 8 if(c=='G') return 4; 9 } 10 int main(){ 11 int a,b,c,d; 12 scanf("%d%d%d%d",&a,&b,&c,&d); 13 for(int i=1;i<=a;++i){ 14 char ch[5],chh='W'; 15 scanf(" %s",ch); 16 agree[zhuan(ch[0])][zhuan(ch[1])][1]=1; 17 agree[1][1][1]=1; 18 } 19 for(int i=1;i<=b;++i){ 20 char ch[5],chh='I'; 21 scanf(" %s",ch); 22 agree[zhuan(ch[0])][zhuan(ch[1])][2]=1; 23 agree[2][2][2]=1; 24 } 25 for(int i=1;i<=c;++i){ 26 char ch[5],chh='N'; 27 scanf(" %s",ch); 28 agree[zhuan(ch[0])][zhuan(ch[1])][3]=1; 29 agree[3][3][3]=1; 30 } 31 for(int i=1;i<=d;++i){ 32 char ch[5],chh='G'; 33 scanf(" %s",ch); 34 agree[zhuan(ch[0])][zhuan(ch[1])][4]=1; 35 agree[4][4][4]=1; 36 } 37 char name[3500]; 38 scanf(" %s",name); 39 int n=strlen(name); 40 for(int i=0;i<n;++i) dp[i][i][zhuan(name[i])]=1; 41 for(int d=2;d<=n;++d) 42 for(int i=0,j;(j=i+d-1)<n;++i){ 43 for(int k=i;k<j;++k){ 44 for(int u=1;u<=4;++u) 45 if(dp[i][k][u]==1) 46 for(int g=1;g<=4;++g) 47 if(dp[k+1][j][g]==1) 48 for(int x=1;x<=4;++x) 49 if(agree[u][g][x]) 50 dp[i][j][x]=1; 51 } 52 } 53 int flag=0; 54 for(int i=1;i<=4;++i) 55 if(dp[0][n-1][i]){ 56 flag=1; 57 if(i==1) printf("W"); 58 if(i==2) printf("I"); 59 if(i==3) printf("N"); 60 if(i==4) printf("G"); 61 } 62 if(!flag) printf("The name is wrong!"); 63 return 0; 64 }
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e6+10; 4 struct Node{ 5 int from,next,to; 6 }edge[N]; 7 int Head[N],tot; 8 void Add(int x,int y){ 9 edge[++tot].to=y; 10 edge[tot].from=x; 11 edge[tot].next=Head[x]; 12 Head[x]=tot; 13 } 14 int dfn[N],low[N],dfn_cnt,scc_cnt,belong[N]; 15 stack<int>sta; 16 void tarjan(int u){ 17 dfn[u]=low[u]=++dfn_cnt; 18 sta.push(u); 19 for(int i=Head[u];i;i=edge[i].next){ 20 int v=edge[i].to; 21 if(!dfn[v]){ 22 tarjan(v); 23 low[u]=min(low[u],low[v]); 24 } 25 else if(!belong[v]) low[u]=min(low[u],dfn[v]); 26 } 27 if(dfn[u]==low[u]){ 28 scc_cnt++; 29 int t; 30 do{ 31 t=sta.top();sta.pop(); 32 belong[t]=scc_cnt; 33 }while(t!=u); 34 } 35 } 36 int ru[N],chu[N]; 37 int main(){ 38 int n; 39 scanf("%d",&n); 40 for(int i=1;i<=n;++i){ 41 int x=1; 42 scanf("%d",&x); 43 while(x){ 44 Add(i,x); 45 scanf("%d",&x); 46 } 47 } 48 for(int i=1;i<=n;++i) 49 if(!dfn[i]) tarjan(i); 50 for(int i=1;i<=tot;++i){ 51 int x=edge[i].from,y=edge[i].to; 52 if(belong[x]!=belong[y]){ 53 chu[belong[x]]++;ru[belong[y]]++; 54 } 55 } 56 int ans1=0,ans2=0; 57 if(scc_cnt==1){ 58 printf("1 0 "); 59 return 0; 60 } 61 for(int i=1;i<=scc_cnt;++i){ 62 if(!ru[i]) ans1++; 63 if(!chu[i]) ans2++; 64 } 65 printf("%d %d ",ans1,max(ans2,ans1)); 66 return 0; 67 }
1 #include<bits/stdc++.h> 2 #define lson (t<<1) 3 #define rson (t<<1|1) 4 #define mid ((l+r)>>1) 5 using namespace std; 6 const int N=1e6+10; 7 struct Tree{ 8 int l,r,Max,lazy; 9 }tree[N<<2]; 10 void pushup(int t){ 11 tree[t].Max=max(tree[lson].Max,tree[rson].Max); 12 } 13 void pushdown(int t){ 14 tree[lson].Max=max(tree[lson].Max,tree[t].lazy); 15 tree[lson].lazy=max(tree[lson].lazy,tree[t].lazy); 16 tree[rson].Max=max(tree[rson].Max,tree[t].lazy); 17 tree[rson].lazy=max(tree[rson].lazy,tree[t].lazy); 18 tree[t].lazy=0; 19 } 20 void change(int t,int l,int r,int cl,int cr,int num){ 21 if(cl>r || cr<l) return; 22 if(cl<=l&&r<=cr){ 23 tree[t].lazy=max(tree[t].lazy,num); 24 tree[t].Max=max(tree[t].Max,num); 25 return; 26 } 27 pushdown(t); 28 if(cr<=mid) change(lson,l,mid,cl,cr,num); 29 else if(cl>mid) change(rson,mid+1,r,cl,cr,num); 30 else{ 31 change(lson,l,mid,cl,cr,num);change(rson,mid+1,r,cl,cr,num); 32 } 33 pushup(t); 34 } 35 int query(int t,int l,int r,int ql,int qr){ 36 if(ql>r || qr<l) return 0; 37 if(ql<=l&&r<=qr){ 38 return tree[t].Max; 39 } 40 pushdown(t); 41 if(qr<=mid) return query(lson,l,mid,ql,qr); 42 else if(ql>mid) return query(rson,mid+1,r,ql,qr); 43 else return max(query(lson,l,mid,ql,qr),query(rson,mid+1,r,ql,qr)); 44 } 45 struct Input{ 46 int x,h,y; 47 }a[N]; 48 int n=0; 49 int tot=0; 50 int b[N]; 51 int main(){ 52 //freopen("a.in","r",stdin); 53 int x,y,z; 54 while(scanf("%d%d%d",&x,&y,&z)==3){ 55 a[++tot].x=x;a[tot].h=y;a[tot].y=z; 56 } 57 for(int i=1;i<=tot;++i){ 58 int x=a[i].x,y=a[i].y,h=a[i].h; 59 change(1,1,10000,x,y-1,h); 60 } 61 for(int i=1;i<=10000;++i) b[i]=query(1,1,10000,i,i); 62 for(int i=1;i<=10000;++i){ 63 //printf("%d %d ",i,b[i]); 64 if(b[i]!=b[i-1]) 65 printf("%d %d ",i,b[i]); 66 } 67 return 0; 68 }
总结:
今天一天还是挺顺心的,上午考试考了自己集训以来的最好成绩(虽然洛谷说今天大凶),然后今天下午也感觉学到了不少东西,和同学们一起刷了一些题,听说11号奥赛生都要回校(我们是不是回不了家了),这样就又能一起练习了,希望明天能够取得一个好成绩吧.