T1:

分析:
画图模拟,发现折叠后的长度会变成折叠位置左右两部分取max,难点在于:折叠后找不到对应的点在哪个位置。
因为n很大,但其实很多位置都是用不到的,所以处理m个操作。
一次操作后,可能会影响到后面的所有操作的位置,于是将操作离线,一次操作后将后面所有将要用到的操作位置都更新。
怎么更新?
例如:1 2 3 4 5 6 7 8
现在折3,下一步折8,8应该变成abs(3-8)=5
因为相当于将节点重新标号了:
1 2 3 4 5 6 7 8
/ / 0 1 2 3 4 5(被翻过的位置不会再有了)
然后长度又被更新成:len=max(len-a[i],a[i])
(相比起来这种神奇又巧妙的方法ssw的模拟好理解多了)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ri register int
#define N 3005
ll a[N];
int main()
{
freopen("fold.in","r",stdin);
freopen("fold.out","w",stdout);
ll n; int m;
scanf("%lld%d",&n,&m);
ll len=n;
for(ri i=1;i<=m;++i) scanf("%lld",&a[i]);
for(ri i=1;i<=m;++i){
if(len==1) break;
for(ri j=i+1;j<=m;++j) a[j]=abs(a[j]-a[i]);//相当于是把左边的翻转过来重新标号了
len=max(len-a[i],a[i]);//被划分成两段 长的那一段是答案
}
printf("%lld\n",len);
}
/*
5 2
3 5
10 3
3 5 2
*/
T2:

M S L R<=1e9
分析:
先写出式子:L <= (S*x) mod M <= R
移项化简: (-r mod s ) <= M*y mod s <= ( -L mod s )(不知道为什么同%s可以成立,感性理解吧)
将这个问题转换成了子问题,递归求解即可。
细节一堆。。。
先找到可行的简单解作为边界:
若L<=S*x<=R,则x是一个可行解。
若S%M==0,且L不为0,则无解。
详见代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll dfs(ll m,ll s,ll l,ll r)
{
if(l==0) return 0;
if(l>r || s%m==0 || l>=m) return -1;//如果s%m==0而l又不为0 显然无解
s%=m;//没有会超时!! 因为s再大也没有用 最后的式子都是要mod m的
ll tmp=(l-1)/s+1;//ceil 相当于上取整
if(tmp*s>=l && tmp*s<=r) return tmp;//找到第一个是s的倍数 且在范围内的数
ll mm=s,ss=m,lr=(-r%s+s)%s,rr=(-l%s+s)%s;//递归求解
tmp=dfs(mm,ss,lr,rr);
if(tmp==-1) return -1;
ll x=(m*tmp+r)/s;//取一边的r算出一个x,再看这个x是否大于等于l
if(x*s-m*tmp>=l) return (x%m+m)%m;//%m+m%m 保证x为最小正整数
return -1;
}
int main()
{
freopen("solve.in","r",stdin);
freopen("solve.out","w",stdout);
int T;
scanf("%d",&T);
while(T--){
ll m,s,l,r;
scanf("%lld%lld%lld%lld",&m,&s,&l,&r);
if(m<=l) { printf("-1\n"); continue; }
printf("%lld\n",dfs(m,s,l,min(m-1,r)));//注意上界要和m-1取min
}
}
/*
1
5 4 2 3
*/
T3:

分析:
一眼数位dp,但是dp状态的设置很重要。
设dp[i][j][s1][s2]为:现在在第i位,当前前缀的长度为j,当前前缀翻转后与l,r分别比较的大小。
如何求当前翻转后的大小关系?
若这一位大于l对应的一位,则是大于,等于则由上一位的大小关系决定。(r同理)
但要考虑到有前导0的情况,所以第一位要强制从1开始,然后枚举第一位从哪个开始即可。

#include<bits/stdc++.h>
using namespace std;
#define usll unsigned long long
#define ri register int
#define N 25
usll dp[N][N][3][3];
int num[N],A[N],B[N],C[N],cnt=0,ltot=0,rtot=0;
void init(usll x,int *num,int &xx)
{
xx=0;
while(x) { num[++xx]=x%10; x/=10; }
}
int cmp(int x,int y,int last)
{
if(x<y) return 0;//<
if(x==y) return last;
return 2;
}
usll dfs(int x,int y,int s1,int s2,int lim)//x是现在到第x位 y是已经填了y位 s1与s2是与l和r相比较的值
{
if(dp[x][y][s1][s2]!=-1 && !lim) return dp[x][y][s1][s2];
if(x==1){
if(y<ltot) s1=0; if(y<rtot) s2=0;//位数不够的话 肯定是小于l或r的
if(s1!=0 && s2!=2) return 1;//当这个数倒过来大于等于l且小于等于r即可
return 0;
}
int up=lim ? C[x-1] : 9;//x-1:是因为这里的x是已经被填的 要枚举的是下一次要填的 对应x-1位
usll ret=0;
for(ri i=0;i<=up;++i){
ret+=dfs(x-1,y+1,cmp(i,A[y+1],s1),cmp(i,B[y+1],s2),lim && i==up);
}
if(!lim) dp[x][y][s1][s2]=ret;
return ret;
}
usll solve()
{
usll ret=0;
memset(dp,-1,sizeof(dp));
for(ri i=1;i<=cnt;++i){
int up=(i==cnt) ? C[cnt] : 9;//cnt->highest
for(ri j=1;j<=up;++j)
//枚举i 指前cnt-i位填0 后i位有值 比较的是A[1]因为翻转后 这一位相当于l的最后一位 而最后一位对应的下标是1
//last定义为1 是因为如果这一位与l相同 则当作相同 不会出现l的位数大于填的数的情况 因为在dfs里面已经考虑了
ret+=dfs(i,1,cmp(j,A[1],1),cmp(j,B[1],1),i==cnt && j==up);//j==up && up==C[cnt]
}
return ret;
}
int main()
{
freopen("reverse.in","r",stdin);
freopen("reverse.out","w",stdout);
int T,a,b; usll l,r;
scanf("%d%d%d",&T,&a,&b);
while(T--){
cin>>l>>r;
memset(A,0,sizeof(A)); memset(B,0,sizeof(B)); memset(C,0,sizeof(C));
init(l,A,ltot); init(r,B,rtot);
init(r,C,cnt);
usll ans=solve();
init(l-1,C,cnt),ans-=solve();
cout<<ans<<endl;
}
}
/*
3 0 0
1 10
10 20
123 12345
7 0 1
83 9503
83 23773
1 14605
22 25083
10 27604
*/

