noip模拟测试21
Posted gkeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了noip模拟测试21相关的知识,希望对你有一定的参考价值。
T1:折纸
这道写崩我也是没话说……
模拟就完了,记录每次的折叠点,每次将之前的都扫一遍就完了
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstdlib> 7 #define ll long long 8 using namespace std; 9 const int MAXM=50000; 10 ll n,m,pos[MAXM],l,r; 11 int main() 12 scanf("%lld%lld",&n,&m); 13 l=0LL;r=n; 14 for(int i=1,p;i<=m;i++) 15 scanf("%lld",&pos[i]); 16 ll tmp=pos[i]; 17 for(int j=1;j<i;j++) 18 if(pos[j]<tmp) tmp=2*pos[j]-tmp; 19 pos[i]=tmp; 20 l=min(l,2*tmp-r),r=tmp; 21 if(l>r) swap(l,r); 22 23 printf("%lld\n",r-l); 24 return 0; 25
T2:不等式
推了一个多小时……
$L \leq S*x mod M \leq R$
→ $L \leq S*x - \lfloor $$ \frac S*x M $$ \rfloor *M \leq R$
→ $S*x - R \leq \lfloor $$ \frac S*x M $$ \rfloor *M \leq S*x - L $
这里是最关键的一步,同时模S
→ $-R \ mod \ S \leq \lfloor $$ \frac S*x M $$ \rfloor * M \ mod \ S \leq -L \ mod \ S$
到这里我们可以发现,式子变成了一个和原式形式相似的式子
在该式中:$ M‘ = S \qquad S‘ = M \ mod \ S \qquad L‘ = -R \ mod \ S \qquad R‘ = -L \ mod \ S $
看到M和S的变化,很容易就会想到exgcd
然后就像exgcd一样向下递归,当式子足够简单的时候计算答案或判断无解
返回答案后再反推出本层x的值
因为是exgcd的形式,只会递归$log$层,所以复杂度正确(虽然我并不会算……)
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstdlib> 7 #define ll long long 8 using namespace std; 9 int T; 10 ll m,s,l,r,ans; 11 bool flag; 12 void solve(ll mm,ll ss,ll L,ll R,ll &x) 13 if(!L) return (void)(x=0); 14 if(mm<=L||L>R||ss%mm==0) return (void)(x=-1); 15 ll tmp=(L-1)/ss+1; 16 if(tmp*ss<=R) return (void)(x=tmp); 17 solve(ss,mm%ss,((-R)%ss+ss)%ss,((-L)%ss+ss)%ss,x); 18 if(x==-1) return; 19 tmp=(R+mm*x)/ss; 20 if(ss*tmp-mm*x>=L) return (void)(x=(tmp%mm+mm)%mm); 21 return (void)(x=-1); 22 23 int main() 24 scanf("%d\n",&T); 25 while(T--) 26 scanf("%lld%lld%lld%lld",&m,&s,&l,&r); 27 solve(m,s,l,r>m?m-1:r,ans); 28 printf("%lld\n",ans); 29 30 return 0; 31
T3:reverse
恶心数位dp
第一眼:“啊,数位dp!”
第二眼:“怎么dp啊!”
一个小时过去了……
第三眼:“暴力,再见!”
……
记忆化搜索
设计状态$f[i][j][s_1][s_2]$表示考虑到第i位,填了j个数,这j个数reverse之后和l,r后j位的大小关系是$s_1和s_2$的个数
但发现前导0很麻烦,看题解学到了一种新的处理方法,枚举数字长度,然后钦定第一位不为零
注意:若当前数字位数小于r或l,在统计答案是需要特判其大小关系
再注意:拆分l和r的数组需要清空!!!
#include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<cstdlib> #define ull unsigned long long using namespace std; const int MAXN=22; int T,A,B,dig[MAXN],dl[MAXN],dr[MAXN],cl,cr; ull l,r,f[MAXN][MAXN][3][3];//0 < ;1 = ;2 > ; ull dfs(int pos,int revp,int cmpl,int cmpr,bool lim) if(!pos) if(revp-1<cl) cmpl=0; if(revp-1<cr) cmpr=0; return cmpl!=0&&cmpr!=2; if(!lim&&f[pos][revp][cmpl][cmpr]!=-1) return f[pos][revp][cmpl][cmpr]; int upr=lim?dig[pos]:9; ull ret=0; for(int i=0;i<=upr;i++) int ncl,ncr; if(i==dl[revp]) ncl=cmpl; else ncl=i>dl[revp]?2:0; if(i==dr[revp]) ncr=cmpr; else ncr=i>dr[revp]?2:0; ret+=dfs(pos-1,revp+1,ncl,ncr,lim&&(i==upr)); if(!lim) f[pos][revp][cmpl][cmpr]=ret; return ret; ull calc(ull x) if(!x) return 0; memset(f,-1,sizeof(f)); int cnt=0; for(ull tmp=x;tmp;tmp/=10) dig[++cnt]=tmp%10; ull ret=0; for(int i=cl;i<=cnt;i++) int upr=i==cnt?dig[i]:9; for(int j=1;j<=upr;j++) int ncl,ncr; if(j==dl[1]) ncl=1; else ncl=j>dl[1]?2:0; if(j==dr[1]) ncr=1; else ncr=j>dr[1]?2:0; ret+=dfs(i-1,2,ncl,ncr,i==cnt&&j==upr); return ret; void clear() cl=0;cr=0;l=0;r=0; memset(dig,0,sizeof(dig)); memset(dl,0,sizeof(dl)); memset(dr,0,sizeof(dr)); int main() scanf("%d%d%d",&T,&A,&B); while(T--) scanf("%llu%llu",&l,&r); for(ull tmp=l;tmp;tmp/=10) dl[++cl]=tmp%10; for(ull tmp=r;tmp;tmp/=10) dr[++cr]=tmp%10; printf("%llu\n",calc(r)-calc(l-1)); clear(); return 0;
(多测不清空,爆零两行泪)
以上是关于noip模拟测试21的主要内容,如果未能解决你的问题,请参考以下文章