10 11
再次发现自己很菜的样子 什么都不会 还很弱。今天得分150分. T1 50分 T2 100分 T3 0分。
应该可以200+的但是没有把握好机会 很遗憾 很难受qwq. 有的时候优化的方向是一定的就不要再去思考其他的东西了。
这道题 一个 比较简单的dp 我写了好半天于是心态爆炸。关键是我没有想好如何dp 盲目转移了调半天才知道自己是...
当然除了基础状态每次的方案数也要统计不然 显然会挂掉。于是我们就可以快速得到50分的代码。
//#include<bits/stdc++.h> #include<iostream> #include<cstdio> #include<ctime> #include<cstring> #include<string> #include<queue> #include<deque> #include<cmath> #include<algorithm> #include<vector> #include<cctype> #include<cstdlib> #include<utility> #include<bitset> #include<set> #include<map> #include<stack> #include<iomanip> #define INF 1000000010 #define ll long long #define min(x,y) ((x)>(y)?(y):(x)) #define max(x,y) ((x)>(y)?(x):(y)) #define db double #define EPS 1e-5 #define mod 1000000007 using namespace std; char *fs,*ft,buf[1<<15]; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline ll read() { ll x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } const ll MAXN=1000010; ll n; ll a,b,c,d,e; ll f[MAXN][2],g[MAXN][2]; signed main() { //freopen("1.in","r",stdin); freopen("queue.in","r",stdin); freopen("queue.out","w",stdout); n=read(); a=read();b=read();c=read();d=read();e=read(); f[0][0]=d;f[0][1]=e; g[0][0]=1;g[0][1]=1; for(int i=1;i<=n;++i) { if(i-a>=0) { f[i][0]=(f[i][0]+f[i-a][0]+d*g[i-a][0])%mod; g[i][0]=(g[i][0]+g[i-a][0])%mod; } if(i-b>=0) { f[i][0]=(f[i][0]+f[i-b][1]+d*g[i-b][1])%mod; g[i][0]=(g[i][0]+g[i-b][1])%mod; } if(i-c>=0) { f[i][1]=(f[i][1]+f[i-c][1]+e*g[i-c][1])%mod; g[i][1]=(g[i][1]+g[i-c][1])%mod; } if(i-b>=0) { f[i][1]=(f[i][1]+f[i-b][0]+e*g[i-b][0])%mod; g[i][1]=(g[i][1]+g[i-b][0])%mod; } } //cout<<g[n][0]<<' '<<g[n][1]<<endl; printf("%lld\n",(f[n][0]+f[n][1])%mod); return 0; }
观察这个式子我们很显然有优化就是 矩阵乘法 或者 继续考虑这道题想一下组合的做法。
于是我后悔了有式子了不优化那不是sb么 非得去想什么组合数况且自己组合数什么的也没学的怎么好GG。
直接上矩阵好了 这个矩阵还是挺好优化的。其实无非就是把这堆东西全部都放在同一行 然后列出转移矩阵即可。
关键我最愚蠢的地方是 题目都提示了矩阵乘法了a b c 都只有30大小 我都没想着搞矩阵 却因为自己想着这个矩阵可能太大了会超时什么的 真愚蠢。
关键是 我还是对矩阵不敏感 这个递推式只和后面的一项有关 多项有关那就 直接上矩阵了。以后要敏感一点。
//#include<bits/stdc++.h> #include<iostream> #include<queue> #include<iomanip> #include<cctype> #include<cstdio> #include<deque> #include<utility> #include<cmath> #include<ctime> #include<cstring> #include<string> #include<cstdlib> #include<vector> #include<algorithm> #include<stack> #include<map> #include<set> #include<bitset> #define max(x,y) ((x)>(y)?(x):(y)) #define min(x,y) ((x)>(y)?(y):(x)) #define INF 1000000000 #define ll long long #define db double #define mod 1000000007 #define pii pair<ll,ll> #define mk make_pair using namespace std; char buf[1<<15],*fs,*ft; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline ll read() { ll x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } const ll MAXN=121; ll n,m; ll maxx,maxx1,maxx2; ll a,b,c,d,e; ll f[MAXN][2],g[MAXN][2]; struct wy { ll w[MAXN]; ll c[MAXN][MAXN]; wy(){memset(w,0,sizeof(w));memset(c,0,sizeof(c));} friend wy operator *(wy C,wy D) { wy tmp; for(ll i=1;i<=m;++i)tmp.w[i]=C.w[i]; for(ll i=1;i<=m;++i) for(ll j=1;j<=m;++j) for(ll k=1;k<=m;++k) tmp.c[i][j]=(tmp.c[i][j]+C.c[i][k]*D.c[k][j])%mod; return tmp; } friend wy operator -(wy C,wy D) { wy tmp; for(ll i=1;i<=m;++i) for(ll j=1;j<=m;++j) tmp.c[i][j]=C.c[i][j]; for(ll i=1;i<=m;++i) for(ll j=1;j<=m;++j) tmp.w[i]=(tmp.w[i]+C.w[j]*D.c[j][i])%mod; return tmp; } friend wy operator ^(wy A,ll p) { wy tmp=A; while(p) { if(p&1)tmp=tmp-A; p=p>>1; A=A*A; } return tmp; } }A; inline void get_pre(ll x) { f[0][0]=d;f[0][1]=e; g[0][0]=1;g[0][1]=1; for(ll i=1;i<=x;++i) { if(i-a>=0) { f[i][0]=(f[i][0]+f[i-a][0]+d*g[i-a][0])%mod; g[i][0]=(g[i][0]+g[i-a][0])%mod; } if(i-b>=0) { f[i][0]=(f[i][0]+f[i-b][1]+d*g[i-b][1])%mod; g[i][0]=(g[i][0]+g[i-b][1])%mod; } if(i-c>=0) { f[i][1]=(f[i][1]+f[i-c][1]+e*g[i-c][1])%mod; g[i][1]=(g[i][1]+g[i-c][1])%mod; } if(i-b>=0) { f[i][1]=(f[i][1]+f[i-b][0]+e*g[i-b][0])%mod; g[i][1]=(g[i][1]+g[i-b][0])%mod; } } } int main() { //freopen("1.in","r",stdin); freopen("queue.in","r",stdin); freopen("queue.out","w",stdout); n=read(); a=read();b=read();c=read();d=read();e=read(); maxx1=max(a,b);maxx2=max(b,c); maxx=max(maxx1,maxx2); get_pre(maxx); for(ll i=1;i<=maxx;++i)A.w[i]=g[i][0]; A.c[maxx-a+1][maxx]=1;A.c[2*maxx-b+1][maxx]=1; for(ll j=maxx-1;j;--j)A.c[j+1][j]=1; for(ll i=maxx+1;i<=2*maxx;++i)A.w[i]=g[i-maxx][1]; A.c[2*maxx-c+1][2*maxx]=1;A.c[maxx-b+1][2*maxx]=1; for(ll j=maxx*2-1;j>=maxx+1;--j)A.c[j+1][j]=1; for(ll i=maxx*2+1;i<=maxx*3;++i)A.w[i]=f[i-maxx*2][0]; A.c[3*maxx-a+1][maxx*3]=1;A.c[maxx-a+1][maxx*3]=d; A.c[4*maxx-b+1][maxx*3]=1;A.c[2*maxx-b+1][maxx*3]=d; for(ll i=maxx*3-1;i>=maxx*2+1;--i)A.c[i+1][i]=1; for(ll i=maxx*3+1;i<=maxx*4;++i)A.w[i]=f[i-maxx*3][1]; A.c[maxx*4-c+1][maxx*4]=1;A.c[2*maxx-c+1][maxx*4]=e; A.c[maxx*3-b+1][maxx*4]=1;A.c[maxx-b+1][4*maxx]=e; for(ll i=maxx*4-1;i>=maxx*3+1;--i)A.c[i+1][i]=1; //printf("%lld\n",A.w[maxx]); //printf("%lld\n",A.w[2*maxx]); m=maxx<<2;A=A^(n-maxx); //printf("%lld\n",A.w[maxx]); //printf("%lld\n",A.w[2*maxx]); printf("%lld\n",(A.w[maxx*3]+A.w[maxx*4])%mod); return 0; }
、
字符串的问题 LCP 最长公共前缀 。两两匹配问题首先就是 二分图最大带权匹配了。不会KM 能跑费用流啊。
考虑100分 n^2建图都完成不了 考虑 一种更加的匹配方法 题目必然有某些特殊的性质。
考虑二分图转换匹配的问题 一个点把另一个点的对象给占了 的充要条件是 另一个点还有一个对象 且 交换后对答案更优,但是这种情况在LCP出现的时候就变得不再可能了。
证明的话考虑交换后能否得到一个更优的解,(当时想到了,但是没证明qwq 现在看起来也不好证明的样子
画个trie 就可以证明了 把最优解拆散一定不优那么 就是每次选取全局最优解了 但是还是很不好做的样子。
上trie 然后发现LCP很好求全局最优解也很好求 其实核心就是再dfs一遍即可。
//#include<bits/stdc++.h> #include<iostream> #include<queue> #include<iomanip> #include<cctype> #include<cstdio> #include<deque> #include<utility> #include<cmath> #include<ctime> #include<cstring> #include<string> #include<cstdlib> #include<vector> #include<algorithm> #include<stack> #include<map> #include<set> #include<bitset> #define max(x,y) ((x)>(y)?(x):(y)) #define min(x,y) ((x)>(y)?(y):(x)) #define INF 1000000000 #define ll long long #define db double #define mod 1000000007 #define pii pair<int,int> #define mk make_pair using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int MAXN=3000000; int n,ans,len,tot,p,id=1; char a[MAXN]; int t[MAXN][26],sz[MAXN],g[MAXN],d[MAXN]; int A,B; inline void insert() { p=1; for(int i=1;i<=len;++i) { int c=a[i]-'a'; if(!t[p][c])t[p][c]=++id; d[t[p][c]]=d[p]+1; p=t[p][c]; } ++sz[p]; } inline void change() { p=1; for(int i=1;i<=len;++i) { int c=a[i]-'a'; if(!t[p][c]) { ++g[p]; return; } p=t[p][c]; } ++g[p]; } inline void dfs(int x) { for(int i=0;i<=25;++i) { if(t[x][i]) { dfs(t[x][i]); sz[x]+=A; g[x]+=B; } } int w=min(g[x],sz[x]); ans+=w*d[x]; A=sz[x]-w;B=g[x]-w; } int main() { //freopen("1.in","r",stdin); freopen("choose.in","r",stdin); freopen("choose.out","w",stdout); n=read(); for(int i=1;i<=n;++i) { scanf("%s",a+1); len=strlen(a+1); insert(); } for(int i=1;i<=n;++i) { scanf("%s",a+1); len=strlen(a+1); change(); } dfs(1); //cout<<tot<<endl; printf("%d\n",ans); return 0; }
、
我是个sb 没有任何能力 也不会思考 也不会打代码 也不会学习文化课 也不会守护。
我 还有什么用处呢?
首先是区间 修改的问题 线段树很难维护 这种区间立方的区间修改 但是修改次数还是可以维护的我们 可以维护修改次数 然后 每次单点暴力查询。
然后 发现这个幂也很大 但是我们有欧拉降幂直接降到logn 或者还有其他的方法 如倍增(发现倍增真强什么都能搞。
设 f[i][j] 表示 i这个数字经过j个三次幂后变成的数字 那么显然有 f[i][j]=f[f[i][j-1]][j-1];
发现暴力修改复杂度 更高且还没有真正的暴力高 这是因为 考虑 只要区间>=14的我们直接输出Yes 即可。
因为存在一个 命题 设 当前区间为 x 那么这个区间的取值 为 2^x设其没有重复的取值出现 其区间的值域为 [x,x*len] 如果都不相同的话 那么显然有
x*len>=2^x 我们可以断定当2^x >x*len 时必然有 重复的取值出现 因为 此时不会有两个区间值相同且有并集 如果存在那么也同时存在两个不同的集合值相同 但同时 值域已经被爆了 所以必然有重复的数字出现 。
由于上述 命题 两个区间必然不相交 故解得x 为14 ;所以大于等于14的区间都是Yes 剩下的爆搜解决 即可。
我可真的是个sb 写个爆搜不清空数组 写个线段树区间修改都能打错。
//#include<bits/stdc++.h> #include<iostream> #include<cstdio> #include<ctime> #include<cstring> #include<string> #include<queue> #include<deque> #include<cmath> #include<algorithm> #include<vector> #include<cctype> #include<cstdlib> #include<utility> #include<bitset> #include<set> #include<map> #include<stack> #include<iomanip> #define INF 1000000010 #define ll long long #define min(x,y) ((x)>(y)?(y):(x)) #define max(x,y) ((x)>(y)?(x):(y)) #define db double #define EPS 1e-5 #define l(p) t[p].l #define r(p) t[p].r #define sum(p) t[p].sum #define zz p<<1 #define yy p<<1|1 #define mod 1000000007 using namespace std; char *fs,*ft,buf[1<<15]; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } const int MAXN=200010,maxn=1010; int n,m,h,flag,v; int Log[MAXN],a[MAXN],q[MAXN],vis[MAXN]; int f[MAXN][20]; struct wy { int l,r; int sum; }t[MAXN<<2]; inline void build(int p,int l,int r) { l(p)=l;r(p)=r; if(l==r)return; int mid=(l+r)>>1; build(zz,l,mid); build(yy,mid+1,r); } inline void pushdown(int p) { sum(zz)+=sum(p); sum(yy)+=sum(p); sum(p)=0;return; } inline void change(int p,int l,int r) { if(l<=l(p)&&r>=r(p)){++sum(p);return;} int mid=(l(p)+r(p))>>1; if(sum(p))pushdown(p); if(l<=mid)change(zz,l,r); if(r>mid)change(yy,l,r); } inline int ask(int p,int x) { if(l(p)==r(p)){int w=sum(p);sum(p)=0;return w;} int mid=(l(p)+r(p))>>1; if(sum(p))pushdown(p); if(x<=mid)return ask(zz,x); return ask(yy,x); } inline int get_x(int x,int y) { for(int i=0;i<=Log[y];++i) if((1<<i)&y)x=f[x][i]; return x; } inline void dfs(int x,int xx,int w,int p) { if(flag)return; if(x==xx+1) { if(!p)return; if(!w)flag=1; if(w>0)q[++h]=w,vis[w]=1; return; } dfs(x+1,xx,w,p); dfs(x+1,xx,w-a[x]-1,1); dfs(x+1,xx,w+a[x]+1,1); } inline void dfs1(int x,int xx,int w,int p) { if(flag)return; if(x==xx+1) { if(!p)return; if(!w)flag=1; if(w>0)if(vis[w])flag=1; return; } dfs1(x+1,xx,w,p); dfs1(x+1,xx,w-a[x]-1,1); dfs1(x+1,xx,w+a[x]+1,1); } inline void cle() { for(int i=1;i<=h;++i)vis[q[i]]=0; return; } inline int find(int l,int r) { for(int i=l;i<=r;++i) { int w=ask(1,i); a[i]=get_x(a[i],w); } h=0;flag=0; int mid=((l+r)>>1); dfs(l,mid,0,0); if(flag)return 1; dfs1(mid+1,r,0,0); if(flag)return 1; return 0; } signed main() { //freopen("1.in","r",stdin); freopen("birthday.in","r",stdin); freopen("birthday.out","w",stdout); n=read();m=read();v=read(); for(int i=1;i<=n;++i)a[i]=read(); build(1,1,n); for(int i=2;i<=m;++i)Log[i]=Log[i>>1]+1; for(int i=1;i<v;++i)f[i][0]=i*i*i%v; for(int i=1;i<=Log[m];++i) for(int j=1;j<v;++j)f[j][i]=f[f[j][i-1]][i-1]; for(int i=1;i<=m;++i) { int op,l,r; op=read();l=read();r=read(); if(op==1) { if(r-l+1>=14)puts("Yes"); else { cle(); if(find(l,r))puts("Yes"); else puts("No"); } } else change(1,l,r); } return 0; }
复杂度还是很稳的 2*1e8左右