11.11多校聯訓
阿新 • • 發佈:2021-11-14
T1 gem
Sol
只會30分的記搜。以前做過一樣的,這次寫的DP,記錄當前用了幾枚紅/藍寶石,目前最多紅-藍/藍-紅字尾是多少。轉移方程很顯然。
T2 sale
Sol
看完題很快就想到矩陣快速冪,然後發現是原題。
原題CF514E Darth Vader and Tree比這個甚至還多套了一層掩飾。
線性DP很好想,就是列舉種優惠券把去掉後的方案數+1。即\(dp_j=\sum_{i=1}^n dp_{j-d_i}\)。
發現\(n\)比較大而\(d_i\)比較小,所以可以用一個桶記錄每種\(d_i\)的值出現次數。即\(dp_j=\sum_{i=1}^{100}t_i*dp_{j-i}\)
這是一個非常標準的線性DP方程,考慮通過 矩陣加速快速求解。
Code
#include<bits/stdc++.h> using namespace std; #define int long long const int p=1000000007; namespace io { inline int read() { int x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();} while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar(); return f?x:-x; } inline void print(int x) { static int s[40],slen;slen=0; if(x==0){putchar('0');return;} if(x<0)x=-x,putchar('-'); while(x){s[++slen]=x%10;x/=10;} for(int i=slen;i;i--)putchar('0'+s[i]); return; } } using namespace io; struct matrix { int n,m; int a[110][110]; }matans,matx; int n,t[110],k; inline matrix mul(matrix &a,matrix &b) { matrix c;c.n=a.n;c.m=b.m; for(int i=1;i<=101;i++)for(int j=1;j<=101;j++)c.a[i][j]=0; for(int i=1;i<=a.n;i++) { for(int k=1;k<=a.m;k++) { if(a.a[i][k]==0)continue; for(int j=1;j<=b.m;j++) { c.a[i][j]+=(a.a[i][k]*b.a[k][j])%p; if(c.a[i][j]>=p)c.a[i][j]-=p; } } } return c; } inline matrix ksm(matrix a,int mi) { matrix matmp;matmp.n=a.n;matmp.m=a.m; for(int i=1;i<=101;i++)for(int j=1;j<=101;j++)matmp.a[i][j]=0; for(int i=1;i<=a.n;i++)matmp.a[i][i]=1; while(mi) { if(mi&1)matmp=mul(matmp,a); a=mul(a,a);mi>>=1; } return matmp; } signed main() { freopen("sale.in","r",stdin); freopen("sale.out","w",stdout); n=read();k=read(); for(int i=1;i<=n;i++)t[read()]++; matx.a[1][1]=1;matans.n=101;matans.m=1; matx.n=matx.m=101; for(int i=2;i<=101;i++)matx.a[1][i]=matx.a[2][i]=t[i-1]; for(int i=3;i<=101;i++)matx.a[i][i-1]=1; matans.a[1][1]=matans.a[2][1]=1; matx=ksm(matx,k); matans=mul(matx,matans); print(matans.a[1][1]);putchar('\n'); return 0; }
T3 (記不到名字了)
Sol
寫在前面:這個題的互動完全不懂有什麼意義。
又一道原題,不過卡掉了原題的解法。
P7670 [JOI2018] Snake Escaping
先想兩種暴力:
第一種每次查詢直接暴力匹配。時間複雜度\(\mathcal{O}(q*2^n)\)
第二種預處理所有答案,先搜確定0
和1
的,然後2
的就是前兩者之和。時間複雜度\(\mathcal{O}(3^n)\)
於是經過我也不知道怎麼會這樣的思考,發現兩者結合就過了。
取一個引數\(K\),假設前\(K\)位用暴力一,後面的暴力二預處理,那麼時間複雜度就是\(\mathcal{O}(q*2^K+3^{n-K})\),luogu上的題目親測\(K\)
Code(不是互動)
#include<bits/stdc++.h>
using namespace std;
namespace io
{
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar();
return f?x:-x;
}
inline void print(int x)
{
static int s[40],slen;slen=0;
if(x==0){putchar('0');return;}
if(x<0)x=-x,putchar('-');
while(x){s[++slen]=x%10;x/=10;}
for(int i=slen;i;i--)putchar('0'+s[i]);
return;
}
}
using namespace io;
const int maxn=30,maxm=1000010,K=8,L=12,F=(1<<K)-1;
int n,q,o,oo;
int mi3[maxn],mi32[maxn],ans[maxm],a[(1<<20)+10];
int d[maxm],hf[maxm],hb[maxm];
int ansf[531451],lb[531451],ts[531451],td[(1<<20)+10];
char s[21];
inline int dfs(int x)
{
int now=x-o;int &rst=ansf[now];
if(~rst)return rst;
if(lb[now]==-1)return rst=a[ts[now]+oo];
rst=dfs(x-mi3[lb[now]])+dfs(x-mi3[lb[now]]*2);
return rst;
}
int main()
{
n=read();q=read();
for(int i=0;i<(1<<n);i++)a[i]=getchar()-'0';
mi3[0]=1;
for(int i=1;i<=maxn;i++)mi3[i]=mi3[i-1]*3,mi32[i]=mi3[i]<<1;
memset(lb,-1,sizeof(lb));
for(int i=0;i<531451;i++)
{
if(i%3==2)lb[i]=0;
else if(~lb[i/3])lb[i]=lb[i/3]+1;
else lb[i]=lb[i/3];
}
for(int i=0;i<531451;i++)
{
ts[i]=ts[i/3]<<1|i%3;td[ts[i]]=i;
}
if(n<=L)
{
memset(ansf,-1,sizeof(ansf));
for(int i=0;i<mi3[n];i++)dfs(i);
for(int i=1;i<=q;i++)
{
scanf("%s",s+1);
int now=0;
for(int j=1;j<=n;j++)
{
if(s[j]=='?')now=now*3+2;
else now=now*3+s[j]-'0';
}
print(ansf[now]);putchar('\n');
}
return 0;
}
for(int i=1;i<=q;i++)
{
scanf("%s",s+1);
hf[i]=F;
for(int j=1;j<=K;j++)
{
int now=s[j]=='0'?0:1;
d[i]=(d[i]<<1)+now;
if(s[j]=='?')hf[i]=hf[i]^(1<<(K-j));
}
for(int j=K+1;j<=n;j++)
{
int now;
if(s[j]=='?')now=2;
else now=s[j]-'0';
hb[i]=hb[i]*3+now;
}
}
int lim=1<<K;
for(int i=0;i<lim;i++)
{
oo=i<<(n-K),o=td[i]*mi3[n-K];
memset(ansf,-1,sizeof(ansf));
for(int j=0;j<mi3[n-K];j++)dfs(j+o);
for(int j=1;j<=q;j++)
{
if(((d[j]^i)&hf[j])==0)ans[j]+=ansf[hb[j]];
}
}
for(int i=1;i<=q;i++)print(ans[i]),putchar('\n');
return 0;
}
T4
不會。