多校A层冲刺NOIP2024模拟赛04
学校OJ赛时 rank28,T1 0pts,T2 100pts,T3 20pts,T4 25pts
accoders rank15,T1 100pts,T2 100pts,T3 20pts,T4 25pts
不是,也没人告诉我两个OJ文件名不一样啊
02表示法
递归 + 高精除低精。
点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
#define rep(i,s,t,p) for(int i = s;i <= t; i += p)
#define drep(i,s,t,p) for(int i = s;i >= t; i -= p)
#ifdef LOCALFILE *InFile = infile("in.in"),*OutFile = outfile("out.out");FILE *ErrFile=errfile("err.err");
#elseFILE *Infile = infile("power.in"),*OutFile = outfile("power.out");//FILE *ErrFile = stderr;
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
const int N = 200;
string s;
ll n;
inline int divide(string &s){if(!s.size()) return -1;if(s.size() == 1 && s[0] == '0') return -1;if(s.size() == 1 && s[0] == '1'){s = "";return 1;}int res = (s.back() - '0')%2;s.back() -= res;int n = s.size(),x = 0;string sh;bool flag = false;rep(i,0,n-1,1){x = x*10 + (s[i] - '0');if(x >= 2) sh.push_back(x/2+'0'),x %= 2,flag = true;else if(flag) sh.push_back('0');}s = sh;return res;
}
#define pii pair<int,int>
#define mk make_pair
void work(string s){if(s == "0") return cout<<0,void();if(s == "1") return cout<<"1",void();if(s == "2") return cout<<"2",void();if(!s.size()) return;vector<pii> p;rep(i,0,999999,1){int x = divide(s);if(x == -1) break;if(!x) continue;p.emplace_back(mk(i,1));}reverse(p.begin(),p.end());int len = p.size();for(int i = 0;i < len; ++i){if(p[i].first == 1) {cout<<2;goto ed;}cout<<2;if(p[i].first != 1) cout<<'(';work(to_string(p[i].first));if(p[i].first != 1) cout<<')';ed:;if(i != len - 1) cout<<'+';}
}
inline void solve(){cin>>s;work(s);
}
signed main(){cin.tie(nullptr)->sync_with_stdio(false);cout.tie(nullptr)->sync_with_stdio(false);solve();
}
子串的子串
赛时写了一个\(O(nq\log n)\)的暴力,本来是能拿70pts的,但是常数小+信仰就过了。
就是把每次查询的串截出来,然后跑个后缀数组求\(height\),用结论 : 一个字符串本质不同的子串的数量为\(\frac{n\times (n+1)}{2}-\sum_{i=2}^n height_i\),就可以了。
求后缀数组用的倍增法,用\(DC3\)的话就是\(O(nq)\)的
点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
#define rep(i,s,t,p) for(int i = s;i <= t; i += p)
#define drep(i,s,t,p) for(int i = s;i >= t; i -= p)
#ifdef LOCALFILE *InFile = infile("in.in"),*OutFile = outfile("out.out");// FILE *ErrFile=errfile("err.err");
#elseFILE *Infile = infile("substring.in"),*OutFile = outfile("substring.out");//FILE *ErrFile = stderr;
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
const int N = 3010;
char *p1,*p2,buf[1<<23];
#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<23,stdin),p1==p2)?EOF:*p1++)
#ifdef linux
#define pc putchar_unlocked
#else
#define pc putchar
#endif
namespace IO{template<typename T>inline bool read(T &x){x=0;char s=gc();bool f=true;for(;(s<'0'||'9'<s);s=gc()) {if(s=='-') f=false;if(s==EOF)return false;}for(;'0'<=s&&s<='9';s=gc()) x=(x<<1)+(x<<3)+(s^48);if(!f) x=~x+1;return true;}inline bool read(double &x){x=0.0;char s=gc();bool f=true;for(;(s<'0'||'9'<s);s=gc()) {if(s=='-') f=false;if(s==EOF)return false;}for(;'0'<=s&&s<='9';s=gc()) x=(x*10)+(s^48);if(s!='.'){return true;}double res=0.1;s=gc();for(;'0'<=s&&s<='9';res/=10,s=gc()) x+=(s^48)*res;x=f?x:-x;return true;}inline bool read(long double &x){x=0.0;char s=gc();bool f=true;for(;(s<'0'||'9'<s);s=gc()) {if(s=='-') f=false;if(s==EOF)return false;}for(;'0'<=s&&s<='9';s=gc()) x=(x*10)+(s^48);if(s!='.'){return true;}double res=0.1;s=gc();for(;'0'<=s&&s<='9';res/=10,s=gc()) x+=(s^48)*res;x=f?x:-x;return true;}inline bool read(float &x){x=0.0;char s=gc();bool f=true;for(;(s<'0'||'9'<s);s=gc()) {if(s=='-') f=false;if(s==EOF)return false;}for(;'0'<=s&&s<='9';s=gc()) x=(x*10)+(s^48);if(s!='.'){return true;}double res=0.1;s=gc();for(;'0'<=s&&s<='9';res/=10,s=gc()) x+=(s^48)*res;x=f?x:-x;return true;}inline bool read(string &str){string ().swap(str);char s=gc();for(;s==' '||s=='\n';s=gc());if(s==EOF) return false; for(;s!=' '&&s!='\n'&&s!=EOF;s=gc())str.push_back(s);return true;}inline bool read_line(string &str){string ().swap(str);char s=gc();for(;s==' '||s=='\n';s=gc());if(s==EOF) return false;for(;s!='\n'&&s!=EOF;s=gc()){str.push_back(s);}return true;}inline bool read_line(char *str){int len=0;char s=gc();for(;s==' '||s=='\n';s=gc());if(s==EOF) return false;for(;s!='\n'&&s!=EOF;s=gc()){str[len]=s;len++;}str[len]='\0';return true;}inline bool read(char &s){char x=gc();for(;x==' '||x=='\n';x=gc());if(x==EOF||x==' '||x=='\n')return false;s=x;return true;}inline bool read(char *s){int len=0;char x=gc();for(;x==' '||x=='\n';x=gc());if(x==EOF)return false;for(;x!=' '&&x!='\n'&&x!=EOF;x=gc())s[len++]=x;s[len]='\0';return true;}template<class T,class... Args> inline bool read(T &x,Args&... args){return (read(x)&&read(args...));}template<class T>inline void write(T x){static T st[45];int top=0;if(x<0)x=~x+1,pc('-');do{st[top++]=x%10;}while(x/=10);while(top)pc(st[--top]^48);}inline void write(char x){pc(x);}inline void write(string s){for(int i=0;s[i];++i) pc(s[i]);}inline void write(char *s){int len=strlen(s);for(int i=0;i<len;++i) pc(s[i]);}inline void write(const char *s){int len=strlen(s);for(int i=0;i<len;++i) pc(s[i]);}template<class T,class... Args> inline void write(T x,Args... args){write(x);write(args...);}
}using namespace IO;
int n,m,sa[N],rk[N],tp[N],ht[N],ct[N];char s[N],s1[N];
inline void Qsort(int m){rep(i,1,m,1) ct[i] = 0;rep(i,1,n,1) ++ct[rk[i]];rep(i,2,m,1) ct[i] += ct[i-1];drep(i,n,1,1) sa[ct[rk[tp[i]]]--] = tp[i];
}
inline bool cmp(int x,int y,int w){return (tp[x]==tp[y]&&tp[x+w]==tp[y+w]);}
inline void get_sa(){n = strlen(s+1);int m = 27;rep(i,1,n,1) rk[i] = s[i] - 'a' + 1,tp[i] = i;Qsort(m);for(int w=1,p=0;w<=n;m=p,p=0,w<<=1){rep(i,n-w+1,n,1) tp[++p]=i;rep(i,1,n,1) if(sa[i]>w) tp[++p]=sa[i]-w;Qsort(m);rep(i,1,n,1) swap(tp[i],rk[i]);p=rk[sa[1]]=1;rep(i,2,n,1) rk[sa[i]]=cmp(sa[i-1],sa[i],w)?p:++p;if(p==n) break;}int k = 0;rep(i,1,n,1){if(!rk[i]) continue;if(k) --k;while(s[i+k] == s[sa[rk[i]-1]+k]) k++;ht[rk[i]] = k;}
}
inline void solve(){read(n,m);read(s1+1);while(m--){int l,r;ll ans;read(l,r);rep(i,l,r,1) s[i-l+1] = s1[i];n = r-l+1;s[n+1] = '\0';get_sa();ans = 1ll*n*(n+1)/2;rep(i,2,n,1) ans -= ht[i];rep(i,1,n,1) ht[i] = rk[i] = sa[i] = tp[i] = 0;write(ans,'\n');}
}
signed main(){solve();
}
正解是预处理,二维前缀和。
记\(ans_{l,r}\)表示区间\([l,r]\)及其子区间本质不同的字符串的个数。可以先维护差分数组然后前缀和解决。
先枚举子串长度,再枚举左端点,通过预处理的前缀和求出这\([l,r]\)一子串的哈希值,那么该串的左右端
点\([l,r]\)的答案加一,即\(ans_{l,r}++\),为了避免重复统计,该串还在上次该串出现位置到该位置
之间该串都有贡献,那么应该将上一次出现的左端点\(pre\)(字符串哈希维护)与当前右端点的答案减一,
即\(ans_{pre,r}--\),最后对数组求和得到的其实是会有重复贡献,要通过容斥计算出每个区间的答案\(ans_{l,r}\)
,回答询问
点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
#define rep(i,s,t,p) for(int i = s;i <= t; i += p)
#define drep(i,s,t,p) for(int i = s;i >= t; i -= p)
#ifdef LOCALFILE *InFile = infile("in.in"),*OutFile = outfile("out.out");// FILE *ErrFile=errfile("err.err");
#elseFILE *Infile = infile("substring.in"),*OutFile = outfile("substring.out");//FILE *ErrFile = stderr;
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
const int N = 3010;
char s[N];
int n,m,ans[N][N];
ull hs[N],pw[N],base = 131;
inline ull get_hash(int l,int r){return hs[r] - hs[l-1]*pw[r-l+1];}
inline void solve(){cin>>n>>m>>(s+1);pw[0] = 1;rep(i,1,n,1) pw[i] = pw[i - 1] * base;rep(i,1,n,1) hs[i] = hs[i-1]*base + s[i];rep(len,1,n,1){__gnu_pbds::gp_hash_table<ull,int> mp;rep(l,1,n-len+1,1){int r = l + len - 1;ull h = get_hash(l,r);ans[mp[h]][r]--;mp[h] = l;}}drep(l,n,1,1) rep(r,l,n,1)ans[l][r] += ans[l + 1][r] + ans[l][r - 1] - ans[l+1][r-1] + 1;while(m--){int l,r;cin>>l>>r;cout<<ans[l][r]<<'\n';}
}
signed main(){cin.tie(nullptr)->sync_with_stdio(false);cout.tie(nullptr)->sync_with_stdio(false);solve();
}
魔法咒语
考虑一个串是被两个拼起来的或者就一个,一个的特判掉。
考虑对于每一个前缀扩展,假设拓展的第一个字符为\(c\)
加入\(c\)已经被扩展过了,那么看看它是否是最后一个节点,如果是,那么说明这个咒语本身就存在,直接加上一个即可。
反之,那么就考虑所有第一个字符为\(c\)的不同后缀都可以。
前缀的话插入一个正向的Trie就可以,看后缀的话插入一个后缀的Trie即可。
点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
#define rep(i,s,t,p) for(int i = s;i <= t; i += p)
#define drep(i,s,t,p) for(int i = s;i >= t; i -= p)
#ifdef LOCALFILE *InFile = infile("in.in"),*OutFile = outfile("out.out");// FILE *ErrFile=errfile("err.err");
#elseFILE *Infile = infile("magic.in"),*OutFile = outfile("magic.out");//FILE *ErrFile = stderr;
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
const int N = 4e5 + 10;
struct Trie{int tree[N][27],cnt[N],tot;inline void insert(string s,bool rev){int p = 0,len = s.size()-1;if(rev) reverse(s.begin(),s.end());rep(i,0,len,1){int x = s[i] - 'a' + 1;if(!tree[p][x]) tree[p][x] = ++tot,cnt[x] += rev;p = tree[p][x];}}
}t1,t2;
ll ans = 0,n;
string s[N];
bitset<27> ok,flag;
inline void solve(){cin>>n;rep(i,1,n,1){cin>>s[i];t1.insert(s[i],false);t2.insert(s[i],true);int len = s[i].size();ok[s[i].back() - 'a' + 1] = true;if(len == 1 && !flag[s[i][0] - 'a' + 1]) ans++,flag[s[i][0] - 'a' + 1] = true;}rep(i,1,t1.tot,1) rep(j,1,26,1)if(!t1.tree[i][j]) ans += t2.cnt[j];else if(ok[j]) ans++;cout<<ans<<'\n';
}
signed main(){cin.tie(nullptr)->sync_with_stdio(false);cout.tie(nullptr)->sync_with_stdio(false);solve();
}
表达式
线段树。不太懂啊。
将给的模数分解成\(\prod p_i^{k_i}\),然后以每个\(p_i^{k_i}\)为模数,求出答案以后再用CRT合并。
至于以\(p_i^{k_i}\)为模数的处理,用线段树暴力记录就好了。
点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
#define rep(i,s,t,p) for(int i = s;i <= t; i += p)
#define drep(i,s,t,p) for(int i = s;i >= t; i -= p)
#ifdef LOCALFILE *InFile = infile("in.in"),*OutFile = outfile("out.out");// FILE *ErrFile=errfile("err.err");
#elseFILE *Infile = infile("expr.in"),*OutFile = outfile("expr.out");//FILE *ErrFile = stderr;
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
#define fi first
#define se second
#define pii pair<char,int>
#define mk make_pair
const int N = 2e5 + 10;
int n,m,mod;
pii a[N];struct Segment_Tree{struct segment_tree{int l,r,val[30];#define l(k) tree[k].l#define r(k) tree[k].r#define val(k) tree[k].val}tree[N<<2];int p;unordered_map<char,function<int(int,int)> > op = {{'+',[&](int a,int b){return (a+b)%p;}},{'*',[&](int a,int b){return 1ll*a*b%p;}},{'^',[&](int a,int b){int res = 1;for(;b;b >>= 1,a = 1ll*a*a%p) if(b&1) res = 1ll*res*a%p;return res;}}};inline void pushup(int k){rep(i,0,p-1,1) val(k)[i] = val(k<<1|1)[val(k<<1)[i]];}void build(int k,int l = 1,int r = n){l(k) = l,r(k) = r;if(l == r){rep(i,0,p-1,1) val(k)[i] = op[a[l].fi](i,a[l].se);return;}int mid = (l + r) >> 1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);pushup(k);}void change(int k,int pos){if(l(k) == r(k)){rep(i,0,p-1,1) val(k)[i] = op[a[pos].fi](i,a[pos].se);return;}int mid = (l(k) + r(k)) >> 1;if(pos <= mid) change(k<<1,pos);else change(k<<1|1,pos);pushup(k);}
}T[4];
int exgcd(int a,int b,int &x,int &y){if(!b) return x = 1,y = 0,a;int d = exgcd(b,a%b,x,y);int t = x;x = y;y = t - (a/b)*y;return d;
}
namespace TP{const int N = 2e5 + 10;char op[N];int testid,n,m,mod,a[N];inline int power(int a,int b,int mod){int res = 1;for(;b;b>>=1,a = 1ll*a*a%mod) if(b&1) res = 1ll*res*a%mod;return res;}inline void solve(){cin>>n>>m>>mod;rep(i,1,n,1) cin>>op[i]>>a[i];while(m--){int p,x;cin>>p;if(p == 1){cin>>x;rep(i,1,n,1){if(op[i] == '+') x = (0ll+x+a[i])%mod;if(op[i] == '*') x = 1ll*x*a[i]%mod;if(op[i] == '^') x = power(x,a[i],mod);}cout<<x<<'\n';}else{char c;int y;cin>>x>>c>>y;op[x] = c,a[x] = y;}}}
}
inline void solve(){int id;cin>>id;if(id <= 3){TP::solve();return;}cin>>n>>m>>mod;rep(i,1,n,1) cin>>a[i].fi>>a[i].se;vector<int> d;int res = mod;for(int i = 2;i * i <= res; ++i){if(res % i == 0){int k = 1;while(res % i == 0) res /= i,k *= i;d.emplace_back(k);}}if(res > 1) d.emplace_back(res);for(int i = 0;i < d.size(); ++i){T[i].p = d[i],T[i].build(1);}// exit(0);auto get_ans = [&](vector<int> &v){int res = 0;for(int i = 0;i < v.size(); ++i){int m = mod/d[i],b,y;exgcd(m,d[i],b,y);res = (res + 1ll * v[i] * m % mod * b % mod) % mod;}return (res + mod) % mod;};while(m--){int op;cin>>op;if(op == 1){int x;cin>>x;vector<int> v;for(int i = 0;i < d.size(); ++i) v.emplace_back(T[i].tree[1].val[x%T[i].p]);cout<<get_ans(v)<<'\n';}else{int x,z;cin>>x;char y;cin>>y>>z;a[x] = mk(y,z);for(int i = 0;i < d.size();T[i++].change(1,x));}}}
signed main(){cin.tie(nullptr)->sync_with_stdio(false);cout.tie(nullptr)->sync_with_stdio(false);solve();
}