【题解】2022牛客寒假算法基础集训营6
回文大师
知识点:kmp
题解:
设数组为
的翻转,即
对数组求出
数组,然后那数组
和
去做匹配,设
匹配了位置
,则
和
构成了一个回文,对
这个位置的计数
,根据
的性质,设
,则
,因此对
计数的同时还要对
都计数,但是暴力跳
会
。
如果把看作
的父亲,则
数组构成了一颗以
为根节点的树(因为
),跑完
和
的匹配后再在树上进行子树求和即可。
#include <bits/stdc++.h> typedef unsigned long long ull; typedef long long ll; #define inf 0x3f3f3f3f #define rep(i, l, r) for (int i = l; i <= r; i++) #define nep(i, r, l) for (int i = r; i >= l; i--) void sc(int &x) { scanf("%d", &x); } void sc(int &x, int &y) { scanf("%d%d", &x, &y); } void sc(int &x, int &y, int &z) { scanf("%d%d%d", &x, &y, &z); } void sc(ll &x) { scanf("%lld", &x); } void sc(ll &x, ll &y) { scanf("%lld%lld", &x, &y); } void sc(ll &x, ll &y, ll &z) { scanf("%lld%lld%lld", &x, &y, &z); } void sc(char *x) { scanf("%s", x); } void sc(char *x, char *y) { scanf("%s%s", x, y); } void sc(char *x, char *y, char *z) { scanf("%s%s%s", x, y, z); } void out(int x) { printf("%d\n", x); } void out(ll x) { printf("%lld\n", x); } void out(int x, int y) { printf("%d %d\n", x, y); } void out(ll x, ll y) { printf("%lld %lld\n", x, y); } void out(int x, int y, int z) { printf("%d %d %d\n", x, y, z); } void out(ll x, ll y, ll z) { printf("%lld %lld %lld\n", x, y, z); } void ast(ll x,ll l,ll r){assert(x>=l&&x<=r);} using namespace std; const int N=1e6+5,mod=998244353; int n,a[N],b[N],nex[N],ans[N]; int main() { // freopen("1.in", "r",stdin); // freopen("1.out", "w", stdout); sc(n); for(int i=0;i<=n;i++) ans[i]=0; rep(i,1,n) sc(a[i]); nex[0]=-1; for(int i=1;i<=n;i++) { int k=nex[i-1]; while(k!=-1&&a[k+1]!=a[i]) k=nex[k]; nex[i]=k+1; } rep(i,1,n) b[i]=a[i]; reverse(b+1,b+1+n); for(int i=1,j=0;i<=n;i++) { while(j!=-1&&a[j+1]!=b[i]) j=nex[j]; j++; ans[j]++; } for(int i=n;i>=1;i--) ans[nex[i]]+=ans[i]; for(int i=1;i<=n;i++) printf(i==n?"%d\n":"%d ",ans[i]); }
价值序列
知识点:计数
题解:
首先说一个结论:删除一个数,价值必定不增。
证明可以用归纳法,对于显然。
对于,如果删除一个
的位置
,价值不变,如果删除
的位置
,价值也不变。如果删除
或
,答案只可能减少,删除一个数后
的规模减
,由归纳法结论得证。
接下来,考虑删除哪些数答案不会变。
把相等的数看成一个连通块,设为,如果满足
或
(且要满足
),则区间
的数可以全部删除,不影响价值,这样的区间对答案贡献有
种方案。否则区间
的数必须保留一个,这样的区间对答案贡献
种方案。把所有区间的贡献连乘起来就是答案。
#include <bits/stdc++.h> typedef unsigned long long ull; typedef long long ll; #define inf 0x3f3f3f3f #define rep(i, l, r) for (int i = l; i <= r; i++) #define nep(i, r, l) for (int i = r; i >= l; i--) void sc(int &x) { scanf("%d", &x); } void sc(int &x, int &y) { scanf("%d%d", &x, &y); } void sc(int &x, int &y, int &z) { scanf("%d%d%d", &x, &y, &z); } void sc(ll &x) { scanf("%lld", &x); } void sc(ll &x, ll &y) { scanf("%lld%lld", &x, &y); } void sc(ll &x, ll &y, ll &z) { scanf("%lld%lld%lld", &x, &y, &z); } void sc(char *x) { scanf("%s", x); } void sc(char *x, char *y) { scanf("%s%s", x, y); } void sc(char *x, char *y, char *z) { scanf("%s%s%s", x, y, z); } void out(int x) { printf("%d\n", x); } void out(ll x) { printf("%lld\n", x); } void out(int x, int y) { printf("%d %d\n", x, y); } void out(ll x, ll y) { printf("%lld %lld\n", x, y); } void out(int x, int y, int z) { printf("%d %d %d\n", x, y, z); } void out(ll x, ll y, ll z) { printf("%lld %lld %lld\n", x, y, z); } void ast(ll x,ll l,ll r){assert(x>=l&&x<=r);} using namespace std; const int N=1e5+5,mod=998244353; int n,a[N],p2[N]; int main() { // freopen("1.in", "r",stdin); // freopen("1.out", "w", stdout); p2[0]=1; for(int i=1;i<N;i++) p2[i]=p2[i-1]*2%mod; int t;sc(t); int sum=0; while(t--) { scanf("%d",&n); rep(i,1,n) sc(a[i]),ast(a[i],1,1000000000); int ans=1; for(int i=1;i<=n;i++) { int j=i; while(j<n&&a[j+1]==a[i]) j++; if(i-1>=1&&j+1<=n&&(a[i-1]<a[i]&&a[j+1]>a[i]||a[i-1]>a[i]&&a[j+1]<a[i])) ans=1ll*ans*p2[j-i+1]%mod; else ans=1ll*ans*(p2[j-i+1]+mod-1)%mod; i=j; } out(ans); } }
数组划分
知识点:单调栈、并查集
题解:
考虑对做前缀和,设
,对于一个位置
,找到
最小的
满足
,可以证明对于任意
,区间
都是美丽的数组;对于任意
,区间
都不是美丽的数组。
对于区间,直接取
作为第一个区间是最优的。
反证法:如果取是最优的
,由于
,于是有
,如果把
作为第一个区间,
会作为第二个区间,凭空多出一个区间,显然不优。
于是对于每个,需要找到最小的
满足
,可以用单调栈找到。
在单调栈的过程中运行到了位置时,可以求出所有
的答案,此时单调栈上有一些位置
,找到最小的
满足
,那么
的答案为
。
如果在退栈的时间维护一个并查集,让
,并维护每个
对应的下标
,则可以
找到这个
。总的时间复杂度为
。
#include <bits/stdc++.h> typedef unsigned long long ull; typedef long long ll; #define inf 0x3f3f3f3f #define rep(i, l, r) for (int i = l; i <= r; i++) #define nep(i, r, l) for (int i = r; i >= l; i--) void sc(int &x) { scanf("%d", &x); } void sc(int &x, int &y) { scanf("%d%d", &x, &y); } void sc(int &x, int &y, int &z) { scanf("%d%d%d", &x, &y, &z); } void sc(ll &x) { scanf("%lld", &x); } void sc(ll &x, ll &y) { scanf("%lld%lld", &x, &y); } void sc(ll &x, ll &y, ll &z) { scanf("%lld%lld%lld", &x, &y, &z); } void sc(char *x) { scanf("%s", x); } void sc(char *x, char *y) { scanf("%s%s", x, y); } void sc(char *x, char *y, char *z) { scanf("%s%s%s", x, y, z); } void out(int x) { printf("%d\n", x); } void out(ll x) { printf("%lld\n", x); } void out(int x, int y) { printf("%d %d\n", x, y); } void out(ll x, ll y) { printf("%lld %lld\n", x, y); } void out(int x, int y, int z) { printf("%d %d %d\n", x, y, z); } void out(ll x, ll y, ll z) { printf("%lld %lld %lld\n", x, y, z); } void ast(ll x,ll l,ll r){assert(x>=l&&x<=r);} using namespace std; const int N=5e6+5,mod=998244353; int n,q; int l[N],r[N]; ll a[N]; int top,rk[N],s[N],f[N],ans[N]; int getf(int x){return f[x]==x?x:f[x]=getf(f[x]);} int main() { // freopen("6.in","r",stdin); // freopen("11.out","w",stdout); int t;sc(t); int sn=0,sq=0; while(t--) { sc(n,q); ast(n,1,5000000);ast(q,1,5000000); sn+=n;sq+=q; ast(sn,1,5000000);ast(sq,1,5000000); for(int i=1;i<=n;i++) sc(a[i]),ast(a[i],-1000000000,1000000000),a[i]+=a[i-1]; for(int i=1;i<=q;i++) sc(l[i],r[i]),ast(l[i],1,n),ast(r[i],l[i],n),l[i]--,r[i]--; for(int i=1;i<=n;i++) f[i]=i; top=0; for(int i=n,j=q;i>=0;i--) { while(top&&a[s[top]]>=a[i]) { f[s[top]]=i; top--; } s[++top]=i; rk[i]=top; while(j>=1&&l[j]==i) { ans[j]=top-rk[getf(r[j])]+1; j--; } } for(int i=1;i<=q;i++) printf("%d\n",ans[i]); } }
#include <bits/stdc++.h> typedef unsigned long long ull; typedef long long ll; #define inf 0x3f3f3f3f #define rep(i, l, r) for (int i = l; i <= r; i++) #define nep(i, r, l) for (int i = r; i >= l; i--) void sc(int &x) { scanf("%d", &x); } void sc(int &x, int &y) { scanf("%d%d", &x, &y); } void sc(int &x, int &y, int &z) { scanf("%d%d%d", &x, &y, &z); } void sc(ll &x) { scanf("%lld", &x); } void sc(ll &x, ll &y) { scanf("%lld%lld", &x, &y); } void sc(ll &x, ll &y, ll &z) { scanf("%lld%lld%lld", &x, &y, &z); } void sc(char *x) { scanf("%s", x); } void sc(char *x, char *y) { scanf("%s%s", x, y); } void sc(char *x, char *y, char *z) { scanf("%s%s%s", x, y, z); } void out(int x) { printf("%d\n", x); } void out(ll x) { printf("%lld\n", x); } void out(int x, int y) { printf("%d %d\n", x, y); } void out(ll x, ll y) { printf("%lld %lld\n", x, y); } void out(int x, int y, int z) { printf("%d %d %d\n", x, y, z); } void out(ll x, ll y, ll z) { printf("%lld %lld %lld\n", x, y, z); } void ast(ll x,ll l,ll r){assert(x>=l&&x<=r);} using namespace std; const int N=5e6+5,mod=998244353; int n,q; int l[N],r[N]; ll a[N]; int top,rk[N],s[N],f[N],ans[N]; int getf(int x){return f[x]==x?x:f[x]=getf(f[x]);} const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=Getchar(); for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1; for(;isdigit(c);c=Getchar()) x=x*10+c-'0'; return x*f; } void print(int x) { if(x>9) print(x/10); putchar(x%10|'0'); } int main() { // freopen("6.in","r",stdin); // freopen("11.out","w",stdout); int t;t=read(); int sn=0,sq=0; while(t--) { n=read();q=read(); ast(n,1,5000000);ast(q,1,5000000); sn+=n;sq+=q; ast(sn,1,5000000);ast(sq,1,5000000); for(int i=1;i<=n;i++) a[i]=read(),ast(a[i],-1000000000,1000000000),a[i]+=a[i-1]; for(int i=1;i<=q;i++) l[i]=read(),r[i]=read(),ast(l[i],1,n),ast(r[i],l[i],n),l[i]--,r[i]--; for(int i=1;i<=n;i++) f[i]=i; top=0; for(int i=n,j=q;i>=0;i--) { while(top&&a[s[top]]>=a[i]) { f[s[top]]=i; top--; } s[++top]=i; rk[i]=top; while(j>=1&&l[j]==i) { ans[j]=top-rk[getf(r[j])]+1; j--; } } for(int i=1;i<=q;i++) print(ans[i]),putchar('\n'); } }
删除子序列
知识点:贪心
输出行,第
行一个整数为第
组测试用例的答案。
题解:
考虑一个贪心做法,首先取在
中出现的最大位置(设为
),接下来需要找位置
满足
,此时所有满足
且
的位置都可以直接删除,因为它们不可能组成字符串
(它们缺乏
),再继续找
,...,一直找到
结束一轮查找,把所有找到的位置删除,并把答案加
。
重复这个查找过程,直到找不到位置,用栈实现可以做到。
用数据结构实现,比如可以做到
。
#include <bits/stdc++.h> typedef unsigned long long ull; typedef long long ll; #define inf 0x3f3f3f3f #define rep(i, l, r) for (int i = l; i <= r; i++) #define nep(i, r, l) for (int i = r; i >= l; i--) void sc(int &x) { scanf("%d", &x); } void sc(int &x, int &y) { scanf("%d%d", &x, &y); } void sc(int &x, int &y, int &z) { scanf("%d%d%d", &x, &y, &z); } void sc(ll &x) { scanf("%lld", &x); } void sc(ll &x, ll &y) { scanf("%lld%lld", &x, &y); } void sc(ll &x, ll &y, ll &z) { scanf("%lld%lld%lld", &x, &y, &z); } void sc(char *x) { scanf("%s", x); } void sc(char *x, char *y) { scanf("%s%s", x, y); } void sc(char *x, char *y, char *z) { scanf("%s%s%s", x, y, z); } void out(int x) { printf("%d\n", x); } void out(ll x) { printf("%lld\n", x); } void out(int x, int y) { printf("%d %d\n", x, y); } void out(ll x, ll y) { printf("%lld %lld\n", x, y); } void out(int x, int y, int z) { printf("%d %d %d\n", x, y, z); } void out(ll x, ll y, ll z) { printf("%lld %lld %lld\n", x, y, z); } void ast(ll x,ll l,ll r){assert(x>=l&&x<=r);} using namespace std; const int N=1e6+5,mod=998244353; int n,m; char s[N],t[N]; int main() { // freopen("1.in", "r",stdin); // freopen("1.out", "w", stdout); int ts;sc(ts);ast(ts,1,10000); int sum=0; while(ts--) { scanf("%d%d",&n,&m); sc(s+1);sc(t+1); ast(n,1,1000000);ast(m,1,min(n,26)); sum+=n; ast(sum,1,1000000); assert(strlen(s+1)==n);assert(strlen(t+1)==m); rep(i,1,n) ast(s[i],'a','z'); rep(i,1,m) ast(t[i],'a','z'); for(int i=1;i<=m;i++) for(int j=i+1;j<=m;j++) assert(t[i]!=t[j]); vector<int>vc[26]; rep(i,1,n) vc[s[i]-'a'].emplace_back(i); int ans=0; while(true) { bool flag=true; int las=n+1; for(int i=m;i>=1;i--) { while(vc[t[i]-'a'].size()&&vc[t[i]-'a'].back()>=las) vc[t[i]-'a'].pop_back(); if(vc[t[i]-'a'].empty()){flag=false;break;} las=vc[t[i]-'a'].back(); vc[t[i]-'a'].pop_back(); } if(!flag) break; ans++; } out(ans); } }
骑士
知识点:前缀和
题解:发现只要满足即可,维护
的前缀和后缀
,就可以很容易得到答案,时间复杂度
。
#include <bits/stdc++.h> typedef unsigned long long ull; typedef long long ll; #define inf 0x3f3f3f3f #define rep(i, l, r) for (int i = l; i <= r; i++) #define nep(i, r, l) for (int i = r; i >= l; i--) void sc(int &x) { scanf("%d", &x); } void sc(int &x, int &y) { scanf("%d%d", &x, &y); } void sc(int &x, int &y, int &z) { scanf("%d%d%d", &x, &y, &z); } void sc(ll &x) { scanf("%lld", &x); } void sc(ll &x, ll &y) { scanf("%lld%lld", &x, &y); } void sc(ll &x, ll &y, ll &z) { scanf("%lld%lld%lld", &x, &y, &z); } void sc(char *x) { scanf("%s", x); } void sc(char *x, char *y) { scanf("%s%s", x, y); } void sc(char *x, char *y, char *z) { scanf("%s%s%s", x, y, z); } void out(int x) { printf("%d\n", x); } void out(ll x) { printf("%lld\n", x); } void out(int x, int y) { printf("%d %d\n", x, y); } void out(ll x, ll y) { printf("%lld %lld\n", x, y); } void out(int x, int y, int z) { printf("%d %d %d\n", x, y, z); } void out(ll x, ll y, ll z) { printf("%lld %lld %lld\n", x, y, z); } void ast(ll x,ll l,ll r){assert(x>=l&&x<=r);} using namespace std; const int N=2e5+5,mod=998244353; int n,a[N],b[N],h[N]; int main() { // freopen("1.in", "r",stdin); // freopen("1.out", "w", stdout); int t;sc(t);ast(t,1,100000); int sum=0; while(t--) { sc(n); ast(n,1,200000); sum+=n;ast(sum,1,500000); rep(i,1,n) sc(a[i],b[i],h[i]),ast(a[i],1,1000000000),ast(b[i],1,1000000000),ast(h[i],1,1000000000); vector<int>pre(n+2),bk(n+1); rep(i,1,n) pre[i]=max(pre[i-1],a[i]); nep(i,n,1) bk[i]=max(bk[i+1],a[i]); ll ans=0; rep(i,1,n) { ll s=1ll*max(pre[i-1],bk[i+1])-b[i]+1; ans+=max(0ll,s-h[i]); } out(ans); } }
+-串
知识点:分类讨论、模拟
题解:不妨令,每次操作相当于可以让
或者
,每次可以贪心往最优的方向移动,或者也可以分情况进行讨论,时间复杂度
。
#include <bits/stdc++.h> typedef unsigned long long ull; typedef long long ll; #define inf 0x3f3f3f3f #define rep(i, l, r) for (int i = l; i <= r; i++) #define nep(i, r, l) for (int i = r; i >= l; i--) void sc(int &x) { scanf("%d", &x); } void sc(int &x, int &y) { scanf("%d%d", &x, &y); } void sc(int &x, int &y, int &z) { scanf("%d%d%d", &x, &y, &z); } void sc(ll &x) { scanf("%lld", &x); } void sc(ll &x, ll &y) { scanf("%lld%lld", &x, &y); } void sc(ll &x, ll &y, ll &z) { scanf("%lld%lld%lld", &x, &y, &z); } void sc(char *x) { scanf("%s", x); } void sc(char *x, char *y) { scanf("%s%s", x, y); } void sc(char *x, char *y, char *z) { scanf("%s%s%s", x, y, z); } void out(int x) { printf("%d\n", x); } void out(ll x) { printf("%lld\n", x); } void out(int x, int y) { printf("%d %d\n", x, y); } void out(ll x, ll y) { printf("%lld %lld\n", x, y); } void out(int x, int y, int z) { printf("%d %d %d\n", x, y, z); } void out(ll x, ll y, ll z) { printf("%lld %lld %lld\n", x, y, z); } void ast(ll x,ll l,ll r){assert(x>=l&&x<=r);} using namespace std; const int N=1e5+5,mod=998244353; int n,k; char s[N]; int main() { // freopen("1.in", "r",stdin); // freopen("1.out", "w", stdout); int t;sc(t);ast(t,1,100000); int sum=0; while(t--) { scanf("%s",s+1); scanf("%d",&k); n=strlen(s+1); ast(k,1,n);ast(n,1,100000); sum+=n;ast(sum,1,300000); rep(i,1,n) assert(s[i]=='-'||s[i]=='+'); int a=0; rep(i,1,n) if(s[i]=='+') a++; else a--; a=abs(a); if(k<=a/2) out(a-k*2); else { k-=a/2; a%=2; if(a==1) out(1); else out(k%2==0?0:2); } } }
迷宫2
知识点:搜索
题解:可以证明从到
存在一条无环的最短路径。证明可以假设有环,如果有环,去掉环一定能让答案不增。于是问题变为找
的
的最短路径,对于点
,如果
,则
到
的花费为
,到其它三个方向的花费为
。可以开一个双向队列进行
,如果
到
的花费为
则把
压入队首,否则压入队尾,对每个已经更新的点打上标记,每个点最多被压入队列
次。时间复杂度
。
#include <bits/stdc++.h> typedef unsigned long long ull; typedef long long ll; #define inf 0x3f3f3f3f #define rep(i, l, r) for (int i = l; i <= r; i++) #define nep(i, r, l) for (int i = r; i >= l; i--) void sc(int &x) { scanf("%d", &x); } void sc(int &x, int &y) { scanf("%d%d", &x, &y); } void sc(int &x, int &y, int &z) { scanf("%d%d%d", &x, &y, &z); } void sc(ll &x) { scanf("%lld", &x); } void sc(ll &x, ll &y) { scanf("%lld%lld", &x, &y); } void sc(ll &x, ll &y, ll &z) { scanf("%lld%lld%lld", &x, &y, &z); } void sc(char *x) { scanf("%s", x); } void sc(char *x, char *y) { scanf("%s%s", x, y); } void sc(char *x, char *y, char *z) { scanf("%s%s%s", x, y, z); } void out(int x) { printf("%d\n", x); } void out(ll x) { printf("%lld\n", x); } void out(int x, int y) { printf("%d %d\n", x, y); } void out(ll x, ll y) { printf("%lld %lld\n", x, y); } void out(int x, int y, int z) { printf("%d %d %d\n", x, y, z); } void out(ll x, ll y, ll z) { printf("%lld %lld %lld\n", x, y, z); } void ast(ll x,ll l,ll r){assert(x>=l&&x<=r);} using namespace std; const int N=1005,mod=998244353; int n,m,dis[N][N],pre[N][N]; char s[N][N]; int dx[]={1,-1,0,0}; int dy[]={0,0,1,-1}; char dir[]={'D','U','R','L'}; bool vis[N][N]; int main() { // freopen("1.in", "r",stdin); // freopen("1.out", "w", stdout); int t;sc(t);ast(t,1,200); int sum=0; while(t--) { sc(n,m);ast(n,1,1000);ast(m,1,1000); sum+=n*m; ast(sum,1,2000000); rep(i,1,n) sc(s[i]+1),assert(strlen(s[i]+1)==m); rep(i,1,n) rep(j,1,m) assert(s[i][j]=='L'||s[i][j]=='R'||s[i][j]=='U'||s[i][j]=='D'); rep(i,1,n) rep(j,1,m) dis[i][j]=inf,vis[i][j]=false; dis[1][1]=0; deque<pair<int,int>>q; q.push_back({1,1}); while(!q.empty()) { int x=q.front().first,y=q.front().second;q.pop_front(); if(vis[x][y]) continue; vis[x][y]=true; for(int i=0;i<4;i++) { int xx=x+dx[i]; int yy=y+dy[i]; if(xx<1||xx>n||yy<1||yy>m) continue; int ndis=dis[x][y]+(dir[i]!=s[x][y]); if(ndis<dis[xx][yy]) { dis[xx][yy]=ndis; pre[xx][yy]=i; if(ndis==dis[x][y]) q.push_front({xx,yy}); else q.push_back({xx,yy}); } } } printf("%d\n",dis[n][m]); int x=n,y=m; while(!(x==1&&y==1)) { int xx=x-dx[pre[x][y]],yy=y-dy[pre[x][y]]; if(s[xx][yy]!=dir[pre[x][y]]) printf("%d %d %c\n",xx,yy,dir[pre[x][y]]); x=xx;y=yy; } } }
寒冬信使2
知识点:SG函数、博弈
题解:把看作
,把
看作
,可以得到一个
串
,把
状态压缩成
,可以发现操作只会让
的值减少,于是可以记录每个状态的
函数,
的
函数为
输出
,否则输出
。
#include <bits/stdc++.h> typedef unsigned long long ull; typedef long long ll; #define inf 0x3f3f3f3f #define rep(i, l, r) for (int i = l; i <= r; i++) #define nep(i, r, l) for (int i = r; i >= l; i--) void sc(int &x) { scanf("%d", &x); } void sc(int &x, int &y) { scanf("%d%d", &x, &y); } void sc(int &x, int &y, int &z) { scanf("%d%d%d", &x, &y, &z); } void sc(ll &x) { scanf("%lld", &x); } void sc(ll &x, ll &y) { scanf("%lld%lld", &x, &y); } void sc(ll &x, ll &y, ll &z) { scanf("%lld%lld%lld", &x, &y, &z); } void sc(char *x) { scanf("%s", x); } void sc(char *x, char *y) { scanf("%s%s", x, y); } void sc(char *x, char *y, char *z) { scanf("%s%s%s", x, y, z); } void out(int x) { printf("%d\n", x); } void out(ll x) { printf("%lld\n", x); } void out(int x, int y) { printf("%d %d\n", x, y); } void out(ll x, ll y) { printf("%lld %lld\n", x, y); } void out(int x, int y, int z) { printf("%d %d %d\n", x, y, z); } void out(ll x, ll y, ll z) { printf("%lld %lld %lld\n", x, y, z); } void ast(ll x,ll l,ll r){assert(x>=l&&x<=r);} using namespace std; const int N=15,mod=998244353; int n,sg[1<<10]; char s[N]; bitset<105>vis; int main() { // freopen("1.in", "r",stdin); // freopen("1.out", "w", stdout); for(int i=1;i<1<<10;i++) { vis.reset(); for(int j=0;j<10;j++) if(i>>j&1) { if(j==0) vis[sg[i^(1<<j)]]=true; else { for(int k=0;k<j;k++) vis[sg[i^(1<<j)^(1<<k)]]=true; } } while(vis[sg[i]]) sg[i]++; } int t;scanf("%d",&t);ast(t,1,5000); while(t--) { sc(n);ast(n,1,10); sc(s+1);assert(strlen(s+1)==n); int st=0; for(int i=1;i<=n;i++) if(s[i]=='w') st|=1<<(i-1); printf(sg[st]?"Yes\n":"No\n"); } }
A+B问题
知识点:模拟
题解:
数组模拟即可。
#include <bits/stdc++.h> typedef unsigned long long ull; typedef long long ll; #define inf 0x3f3f3f3f #define rep(i, l, r) for (int i = l; i <= r; i++) #define nep(i, r, l) for (int i = r; i >= l; i--) void sc(int &x) { scanf("%d", &x); } void sc(int &x, int &y) { scanf("%d%d", &x, &y); } void sc(int &x, int &y, int &z) { scanf("%d%d%d", &x, &y, &z); } void sc(ll &x) { scanf("%lld", &x); } void sc(ll &x, ll &y) { scanf("%lld%lld", &x, &y); } void sc(ll &x, ll &y, ll &z) { scanf("%lld%lld%lld", &x, &y, &z); } void sc(char *x) { scanf("%s", x); } void sc(char *x, char *y) { scanf("%s%s", x, y); } void sc(char *x, char *y, char *z) { scanf("%s%s%s", x, y, z); } void out(int x) { printf("%d\n", x); } void out(ll x) { printf("%lld\n", x); } void out(int x, int y) { printf("%d %d\n", x, y); } void out(ll x, ll y) { printf("%lld %lld\n", x, y); } void out(int x, int y, int z) { printf("%d %d %d\n", x, y, z); } void out(ll x, ll y, ll z) { printf("%lld %lld %lld\n", x, y, z); } void ast(ll x,ll l,ll r){assert(x>=l&&x<=r);} using namespace std; const int N=4e5+5,mod=998244353; int k,c[N]; char a[N],b[N]; int main() { // freopen("1.in", "r",stdin); // freopen("1.out", "w", stdout); sc(k);ast(k,2,10); sc(a+1);sc(b+1); int n=strlen(a+1),m=strlen(b+1); if(n!=1) assert(a[1]!='0'); if(m!=1) assert(b[1]!='0'); rep(i,1,n) ast(a[i],'0','0'+k-1); rep(i,1,m) ast(b[i],'0','0'+k-1); reverse(a+1,a+1+n); reverse(b+1,b+1+m); rep(i,1,max(n,m)) { if(i<=n) c[i]+=a[i]-'0'; if(i<=m) c[i]+=b[i]-'0'; } n=max(n,m); rep(i,1,n) { c[i+1]+=c[i]/k; c[i]%=k; if(c[n+1]) n++; } for(int i=n;i>=1;i--) putchar(c[i]+'0'); }
牛妹的数学难题(easy version)
知识点:组合数学
题解:首先可以不用考虑,接下考虑有
个
和
个
,如果上述和式中
出现了
个,那么
需要出现
个,于是答案为
。
#include <bits/stdc++.h> typedef unsigned long long ull; typedef long long ll; #define inf 0x3f3f3f3f #define rep(i, l, r) for (int i = l; i <= r; i++) #define nep(i, r, l) for (int i = r; i >= l; i--) void sc(int &x) { scanf("%d", &x); } void sc(int &x, int &y) { scanf("%d%d", &x, &y); } void sc(int &x, int &y, int &z) { scanf("%d%d%d", &x, &y, &z); } void sc(ll &x) { scanf("%lld", &x); } void sc(ll &x, ll &y) { scanf("%lld%lld", &x, &y); } void sc(ll &x, ll &y, ll &z) { scanf("%lld%lld%lld", &x, &y, &z); } void sc(char *x) { scanf("%s", x); } void sc(char *x, char *y) { scanf("%s%s", x, y); } void sc(char *x, char *y, char *z) { scanf("%s%s%s", x, y, z); } void out(int x) { printf("%d\n", x); } void out(ll x) { printf("%lld\n", x); } void out(int x, int y) { printf("%d %d\n", x, y); } void out(ll x, ll y) { printf("%lld %lld\n", x, y); } void out(int x, int y, int z) { printf("%d %d %d\n", x, y, z); } void out(ll x, ll y, ll z) { printf("%lld %lld %lld\n", x, y, z); } void ast(ll x,ll l,ll r){assert(x>=l&&x<=r);} using namespace std; const int N=1e7+5,mod=998244353; int n,k,a[N]; ll f[N],invf[N],p2[N]; ll C(int n,int m) { if(n<m) return 0; return f[n]*invf[m]%mod*invf[n-m]%mod; } int main() { // freopen("1.in", "r",stdin); // freopen("1.out", "w", stdout); f[0]=f[1]=invf[0]=invf[1]=1; rep(i,2,N-1) { f[i]=f[i-1]*i%mod;invf[i]=(mod-mod/i)*invf[mod%i]%mod; } rep(i,2,N-1) invf[i]=invf[i-1]*invf[i]%mod; p2[0]=1; rep(i,1,N-1) p2[i]=p2[i-1]*2%mod; sc(n,k); ast(n,1,10000000); ast(k,1,n); int vis[3]; memset(vis,0,sizeof(vis)); rep(i,1,n) sc(a[i]),ast(a[i],0,2),vis[a[i]]++; ll ans=0; for(int i=0;i<=k;i++) ans=(ans+C(vis[2],i)*p2[i]%mod*C(vis[1],k-i)%mod)%mod; out(ans); }
牛妹的数学难题(hard version)
给出长度为的数组
,求
。
数学课上,老师教了牛牛如何快速求上面式子的和:
$$
于是上述的式子就能够在的时间复杂度内被计算出来。
受到老师的启发,牛牛又想到了如何求的和。为此牛牛感到很兴奋,激动得一整夜都睡不着,第二天,牛牛就开始向牛妹炫耀自己能解决这个问题。
牛妹看到牛牛这个问题,虽然她觉得很简单,但是为了鼓励牛牛勇于发现问题的精神,她还是夸赞了牛牛。
但同时,她又给牛牛提出了一个问题,给你一个整数,你能求
是多少吗?
这可把牛牛难到了,牛牛无法解决这个问题,但是牛牛知道你是一个天才程序员,于是他拿着这个问题来向你求助,作为牛牛的好朋友,你能帮帮他解决牛妹的这个数学难题吗?
由于答案可能很大,你只需要输出答案除以的余数。
输入描述
第一行两个整数。
第二行个整数
。
输出描述
输出一行一个整数,为答案除以的余数。
知识点:多项式
题解:
一道比较入门的分治。
设,有转移
。
可以把看成一个多项式
,根据转移有
。
于是可以得到,可以采用分治
,时间复杂度为
。
表示多项式
的
次项系数。
由于撞题了,所以这个题没了,那么就送给大家当礼物好了:
http://www.51nod.com/Challenge/Problem.html#problemId=1348