1. 程式人生 > 其它 >11.11多校聯訓

11.11多校聯訓

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)\)
第二種預處理所有答案,先搜確定01的,然後2的就是前兩者之和。時間複雜度\(\mathcal{O}(3^n)\)
於是經過我也不知道怎麼會這樣的思考,發現兩者結合就過了。
取一個引數\(K\),假設前\(K\)位用暴力一,後面的暴力二預處理,那麼時間複雜度就是\(\mathcal{O}(q*2^K+3^{n-K})\),luogu上的題目親測\(K\)

取8的時候最優秀而且預處理不卡常。但是UKE實在無奈。
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

不會。