Test 5 for NOIP
来源:互联网 发布:mac pro 关闭手写输入 编辑:程序博客网 时间:2024/05/20 02:21
头大
这个暑假完就要去搞NOIP了。。。
暑假55天也就20次测试。。。为防万一我还是每次测试玩都写个总结。。
课程
鉴于现在就开始模拟noip一考就两天我们吃不消于是变成了隔天考。。八月份回来再实行两天一考。
论T1 RMQ被卡(标答是单调队列) T2数位dp不会 T3线段树不会的尴尬处境。。。
Test 5(0/300)
T1 滑动的窗户
题目描述
在一个包含 n 个元素的数组上,有一个长度为 k 的窗户在从左向右滑动。窗户每滑动到一个位置,我们都可以看到 k 个元素在窗户中。如下的例子所示,假设数组为 [1 3 -1 -3 5 3 6 7],而 k 等于 3 :
对于窗户滑动过的每个位置,请给出窗户内 k 个元素的最小值和最大值。
输入格式
输入的第一行包括两个整数 n,k ,n 表示数组的长度,k 表示窗户的长度。
接下来一行包括 n 个整数,表示这个 n 个元素的数组。
输出格式
输出包含两行,每行包括 n-k+1 个整数。
第一行表示窗户从左到右滑动过程中的最小值。
第二行表示窗户从左到右滑动过程中的最大值。
样例数据 1
输入 [复制]
8 3
1 3 -1 -3 5 3 6 7
输出
-1 -3 -3 -3 3 3
3 3 5 5 6 7
备注
【数据范围】
对于 100% 的数据,3<=n<=1000000,1<=k<=n,数组中的每个元素均在 int 范围内。
MY.CPP
#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<ctime>#include<cctype>#include<cstring>#include<string>#include<algorithm>using namespace std;int l,r;int n,k,num[1000500];int rmq[1000500][23];int rmx[1000500][23];int jud(int a,int b){ if(a>=0&&b>=0) return min(a,b); else if(a>=0&&b<0) return b; else if(a<0&&b>=0) return a; else return -max(-a,-b);}int check(){ for(int j=0;(1<<j)<=n;j++) { for(int i=1;i+(1<<j)-1<=n;i++) { cout<<"rmx["<<i<<"]["<<j<<"] = "<<rmx[i][j]<<endl; } cout << endl; } cout << endl;}void init(){ for(int i=1;i<=n;i++)rmq[i][0] = rmx[i][0] = num[i]; for(int j=1;(1<<j)<=n;j++) { for(int i=1;i+(1<<j)-1<=n;i++) { rmq[i][j] = max(rmq[i][j-1],rmq[i+(1<<(j-1))][j-1]); rmx[i][j] = min(rmx[i][j-1],rmx[i+(1<<(j-1))][j-1]); } }}int main(){ freopen("window.in","r",stdin); freopen("window.out","w",stdout); cin >> n >> k; for(int i=1;i<=n;i++) cin >> num[i]; init(); l=0,r=k-1; int ky = (int)(log(k)/log(2)); for(int i=1;i<=n-k+1;i++) { l+=1; r+=1; cout << min(rmx[l][ky],rmx[r-(1<<ky)+1][ky]) << " "; } l=0,r=k-1; cout << endl; for(int i=1;i<=n-k+1;i++) { l+=1; r+=1; cout << max(rmq[l][ky],rmq[r-(1<<ky)+1][ky]) << " "; } return 0;}
所以说比赛时还要注意时间限制,空间限制。。贸然用RMQ的后果就是被心狠的出题人摆了一套全部ME。。
标算是单调队列。RMQ(N*logN),单调(N)
STD.CPP
#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<ctime>#include<cctype>#include<cstring>#include<string>#include<algorithm>#include<vector>using namespace std;int n,k,head,tail;int sta[1000050];int pos[1000050];inline int read(){ int data=0,w=1; char ch=0; while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar(); if(ch=='-') w=-1,ch=getchar(); while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar(); return data*w;}inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0');}int main(){ n=read(); k=read(); for(int i=1;i<=n;i++) sta[i]=read(); head = tail = 0; for(int i=1;i<=n;i++) { while(head<tail&&pos[head]<=i-k)++head; while(head<tail&&sta[pos[tail-1]]>=sta[i])--tail; pos[tail] = i; tail += 1; if(i>=k) write(sta[pos[head]]),cout << " "; } cout << endl; head = tail = 0; for(int i=1;i<=n;i++) { while(head<tail&&pos[head]<=i-k)++head; while(head<tail&&sta[pos[tail-1]]<=sta[i])--tail; pos[tail] = i; tail += 1; if(i>=k) write(sta[pos[head]]),cout << " "; }}
死的只有那么服气。
T2 准考证号(0/100)
题目描述
CLC NOIP2015 惨跪,他依稀记得他的准考证号是 37(其实是假的),现在CLC又将要面临一场比赛,他希望准考证号不出现 37(连续),同时他又十分讨厌 4 ,所以也不希望 4 出现在准考证号中。现在他想知道在 A 和 B 之间有多少合法的准考证号
输入格式
输入包含两个整数,A B。
输出格式
输出一个整数。
样例数据 1
输入 [复制]
1 10
输出
9
样例数据 2
输入 [复制]
25 50
输出
14
备注
【数据规模和约定】
20% 的数据,满足:1<=A<=B<=1000000 。
100% 的数据,满足:1<=A<=B<=2000000000 。
MY.CPP
#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<ctime>#include<cctype>#include<cstring>#include<string>#include<algorithm>using namespace std;long long a,b,a1,b1;int cnts=0,cntt=0;int s[15],t[15];int f[10][10],g4[15];int get(long long num,int jud){ int res=0; while(num) { if(!jud) s[++cnts]=num%10; else s[++cntt]=num%10; res+=1; num/=10; } return res;}void initi(){ int res = 0,jud = 1; for(int i=1;i<=10;i++) { jud = jud*i; res = res+jud; g4[i] = res; }}int get4(int num,int cnt){ if(num<4) cnt-=1; return g4[cnt];} int g37[10] = {0,0,1,2,4,7,12,20,32,50};int get37(int num,int cnt){ if(num<4) cnt-=1; return g37[cnt];}int main(){ freopen("ticket.in","r",stdin); freopen("ticket.out","w",stdout); cin >> a >> b; initi(); a1 = get(a,0); b1 = get(b,1); int ans1=0,ans2=0; for(int i=b1;i>=1;i--) { ans1 += get4(s[i],i) + get37(s[i],i); } for(int i=a1;i>=1;i--) ans2 += get4(s[i],i) + get37(s[i],i); cout << ans1-ans2 << endl; return 0;}
一通乱搞想搞出数位dp。。。但这乱搞得八竿子都打不着也是可以。。
答案就是数位dp,而且几乎是裸题。(不要62)
STD.CPP
#include<iostream>#include<iomanip>#include<cstdio>#include<cstdlib>#include<string>#include<cstring>#include<algorithm>#include<cmath>using namespace std;long long n,m;int a[10],dp[10][3];long long calc(long long x){ long long sum = x; long long ans = 0; int num = 0; bool flag = false; while(x) { a[++num] = x%10; x/=10; } a[num+1] = 0; for(int i=num;i>=1;i--) { ans += dp[i-1][2]*a[i]; if(flag) ans += dp[i-1][0]*a[i]; else { if(a[i]>4) ans += dp[i-1][0]; if(a[i+1]==3&&a[i]>7) ans += dp[i][1]; if(a[i]>3) ans += dp[i-1][1]; if(a[i]==4||(a[i+1]==3&&a[i]==7)) flag = true; } } if(flag) ans++; return sum-ans;}void initi(){ memset(dp,0,sizeof(dp)); dp[0][0] = 1; for(int i=1;i<=9;i++) { dp[i][0] = dp[i-1][0]*9 - dp[i-1][1]; dp[i][1] = dp[i-1][0]; dp[i][2] = dp[i-1][0] + dp[i-1][1] + dp[i-1][2]*10; }}int main(){ initi(); cin >> n >> m; cout << calc(m) - calc(n-1) << endl;}
T3 Query(0/100)
题目描述
万恶的大头又出现了!他正在玩一个智障游戏:打怪兽。
现在大头的屏幕上出现了一排怪兽,每只怪兽头上有一个血条,每次大头可以选择一个区间进行攻击,攻击值为 K ,这个区间中血量小于 K 的怪兽都会被大头无情地干掉,当然怪兽不会坐以待毙,对于一个区间的怪兽,他们会在某个时刻血量同时加 X 。
大头头虽然很大,但是 IQ 并不高,在座的各位选手都不知道比他高到哪里去了。这个时候大头使出了大招——作弊器,然而大头的作弊器并不高级只能将选择的区间内血量为 7 的倍数的怪兽干掉,问:他能干掉多少怪兽?
输入格式
第一行一个正整数 n ;
接下来 n 行 n 个整数;
再接下来一个正整数 Q ,表示操作的个数;
接下来 Q 行每行若干个整数。如果第一个数是 add ,后接 3 个正整数 a,b,X,表示在区间 [a,b] 内每个数增加 X,如果是 count,表示统计区间 [a,b] 能被 7 整除的个数。
输出格式
对于每个询问输出一行一个答案。
样例数据 1
输入 [复制]
3
2 3 4
6
count 1 3
count 1 2
add 1 3 2
count 1 3
add 1 3 3
count 1 3
输出
0
0
0
1
MY.CPP
#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<ctime>#include<cctype>#include<cstring>#include<string>#include<algorithm>using namespace std;int n,q,cnt,mos[100050],pie[320][10],pos[20];int a,b,x;char c[10];void add(){ cin >> a >> b >> x; int l = a/cnt+1; int r = b/cnt-1; if(l<=r) { for(int i=a;i<=l*cnt;i++) { pie[l-1][mos[i]]-=1; mos[i] = (mos[i]+x)%7; pie[l-1][mos[i]]+=1; } for(int i=l+1;i<=r;i++) { for(int j=0;j<=6;j++) pos[j+x] = pie[i][j]; for(int j=0;j<=6;j++) pie[i][(j+x)%7] = pos[j+x]; for(int j=1;j<=cnt;j++) mos[i*cnt+j] = (mos[i*cnt+j]+x)%7; } for(int i=(r+1)*cnt+1;i<=b;i++) { pie[r][mos[i]]-=1; mos[i] = (mos[i]+x)%7; pie[r][mos[i]]+=1; } } else if(l>r) { if(l==r+1) { for(int i=a;i<=l*cnt;i++) { pie[l-1][mos[i]]-=1; mos[i] = (mos[i]+x)%7; pie[l-1][mos[i]]+=1; } for(int i=(r+1)*cnt+1;i<=b;i++) { pie[r][mos[i]]-=1; mos[i] = (mos[i]+x)%7; pie[r][mos[i]]+=1; } } else { for(int i=a;i<=b;i++) { pie[r+1][mos[i]]-=1; mos[i] = (mos[i]+x)%7; pie[r+1][mos[i]]+=1; } } }}void count(){ int ans = 0; cin >> a >> b ; int l = a/cnt+1; int r = b/cnt-1; if(l<=r) { for(int i=a;i<=l*cnt;i++) if(mos[i]==0) ans += 1; for(int i=l;i<=r;i++) ans += pie[i][0]; for(int i=r*cnt+1;i<=b;i++) if(mos[i]==0) ans += 1; } else if(l>r) { if(l==r+1) { for(int i=a;i<=l*cnt;i++) if(mos[i]==0) ans += 1; for(int i=(r+1)*cnt+1;i<=b;i++) if(mos[i]==0) ans += 1; } else { for(int i=a;i<=b;i++) if(mos[i]==0) ans += 1; } } cout << ans << endl;}int main(){ freopen("seg.in","r",stdin); freopen("seg.out","w",stdout); cin >> n; cnt = int(sqrt(n)); for(int i=1;i<=n;i++) { cin >> mos[i]; mos[i] = mos[i]%7; pie[i/cnt+1][mos[i]]+=1; } cin >> q; while(q--) { cin >> c; if(c[0]=='a') add(); else count(); } return 0;}
考试时看到区间就想到了之前讲过的分块(小伙子有想法),但是只有理论又没有打过代码那只有GG一条路可走。。。分块事后证明只会有几个点TE。
标答是线段树。。而且是和模板出入很大的那种。
STD.CPP
//std ans of day* t3 线段树 #include<iostream>#include<algorithm>#include<cmath>#include<ctime>#include<cctype>#include<cstdio>#include<queue>#include<cstring>#include<map>using namespace std;const int Maxn=1e5+50;char ch[10];int a[Maxn],sum[Maxn<<2][8],tag[Maxn<<2];int S[8];inline int read(){ char ch=getchar(); int i=0,f=1; while(!isdigit(ch)) { if(ch=='-')f=-1; ch=getchar(); } while(isdigit(ch)) { i=(i<<1)+(i<<3)+ch-'0'; ch=getchar(); } return i*f;}inline void update(int now){ for(int i=0;i<7;++i) sum[now][i]=sum[now<<1][i]+sum[now<<1|1][i];}inline void build(int k,int l,int r){ if(l==r) { ++sum[k][a[l]]; return; } int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); update(k);}inline void addtag(int k,int v){ tag[k]=(tag[k]+v)%7; for(int i=0;i<7;++i) { int t=(i+v)%7; S[t]=sum[k][i]; } for(int i=0;i<7;++i) sum[k][i]=S[i];}inline void pushdown(int k){ addtag(k<<1,tag[k]); addtag(k<<1|1,tag[k]); tag[k]=0;}inline int query(int k,int l,int r,int L,int R){ if(l>=L&&r<=R) return sum[k][0]; if(tag[k]) pushdown(k); int mid=(l+r)>>1; if(R<=mid) return query(k<<1,l,mid,L,R); else if(L>mid) return query(k<<1|1,mid+1,r,L,R); else return query(k<<1,l,mid,L,R)+query(k<<1|1,mid+1,r,L,R);}inline void modify(int k,int l,int r,int L,int R,int v){ if(l>=L&&r<=R) { addtag(k,v); return; } if(tag[k]) pushdown(k); int mid=(l+r)>>1; if(R<=mid) modify(k<<1,l,mid,L,R,v); else if(L>mid) modify(k<<1|1,mid+1,r,L,R,v); else { modify(k<<1,l,mid,L,R,v); modify(k<<1|1,mid+1,r,L,R,v); } update(k);}int main(){ int n=read(); for(int i=1;i<=n;++i) a[i]=read()%7; build(1,1,n); int Q=read(); while(Q--) { scanf("%s",ch+1); int x=read(),y=read(); if(ch[1]=='c') cout<<query(1,1,n,x,y)<<endl; else { int v=read()%7; modify(1,1,n,x,y,v); } } return 0;}
。。当成是吃一堑长一智吧。。这周搞搞数位DP。。线段树额。。搞搞吧。。
我还想搞KMP和AC自动机来着。。orz
- Test 5 for NOIP
- *TEST 5 for NOIP 。。。
- Test 7 for NOIP
- Test 6 for NOIP
- Test 10 for NOIP
- tEST 2 for NOIP
- tEST 3 for NOIP
- *TEST 1 for NOIP
- *TEST 6 for NOIP + NOIP初赛
- Test 1 for NOIP: Result for Day1
- Test 1 for NOIP: Result for Day2
- Test 2 for NOIP- Result for Day1
- Test 2 for NOIP- Result for Day2
- Test 3 for NOIP- Result for Day2
- Test 4 for NOIP- Result for Day1
- Test 4 for NOIP- Result for Day2
- Test 8 for NOIP- Result for Day1
- Test 8 for NOIP- Result for Day2
- GCD HDU
- D. Misha, Grisha and Underground(LCA 倍增)
- PL/SQL学习总结(1)
- 【ReviewBoard】安装与配置
- 数据表记录包含表索引和数值,请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出。 输入描述: 先输入键值对的个数 然后输入成对的index和value值,以
- Test 5 for NOIP
- 关于弹性调度系统设计细节
- c下的不常用的字符串操作
- 使用docker安装lamp
- python-面向对象
- 机械陀螺仪(ADS8327, STM32F405RGT6)的研究总结报告(连载)
- lintcode -- 电话号码的字母组合
- 暑期集训之ACboy needs your help again!
- Android横竖屏切换时,状态和信息的维护