【比賽】高一下三調

wlesq發表於2024-05-03

A. 李時珍的皮膚衣

看不出規律就打表

點選檢視程式碼
#include <bits/stdc++.h>
#define ll __int128
using namespace std;
long long n;
void p(ll x)
{
	if(!x)return;
	p(x/10);
	cout<<int(x%10);
}
ll qpow(ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1)ans=ans*a%n;
		a=a*a%n;
		b>>=1;
	}
	return ans;
}
int main()
{
	freopen("lsz.in","r",stdin);
	freopen("lsz.out","w",stdout);	
	cin>>n;
	ll pp=(qpow(2,n-1)+1+n)%n;
	if(!pp)cout<<0;
	else p(pp);
	return 0;
}

B. 馬大嘴的廢話

首先如果用hash話會T

Hash
#include <bits/stdc++.h>
#define ll long long
#define ull long long
using namespace std;
const int N =1e4+5,B=233;
int n,m,len[N];ull ha[N][25],p[25];
string s,x;
void get(int d)
{
	len[d]=s.size();
	for(int i=1;i<=len[d];i++)
	{
		ha[d][i]=ha[d][i-1]*B+s[i-1];		
	}
}
ull Hash(int l,int r,int i)
{
	return ha[i][r]-ha[i][l-1]*p[r-l+1];
}
int main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	freopen("mdz.in","r",stdin);
	freopen("mdz.out","w",stdout);	
	cin>>n;
	p[0]=1;
	for(int i=1;i<=20;i++)p[i]=p[i-1]*B;
	for(int i=1;i<=n;i++)
	{
		cin>>s;
		get(i);
	}
	cin>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>x;
		ull has=0;
		int l=x.size();
		for(int i=1;i<=l;i++)
		{
			has=has*B+x[i-1];		
		}
		int ans=0;
		for(int j=1;j<=n;j++)
		{
			if(len[j]<l)continue;
			else 
			{
				for(int st=1;st<=len[j]-l+1;st++)
				{
					if(Hash(st,st+l-1,j)==has)
					{
						ans++;
						break;
					}
				}
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

我們可以考慮字典樹,如何在樹中插入呢,當輸入一個字串時,不能只插入一個整串,這樣不方便查詢,必須把這個字串的子串插入,方便查詢,用一個陣列同步記錄每個字元出現次數

然後需要用陣列記錄一下當前子串屬於那個整串,防止記重

最佳化後
#include <bits/stdc++.h>
#define ll long long
#define ull long long
using namespace std;
const int N =1e4+5,B=233;
int n,m;int son[N*50][27],num[N*50][27],cnt=1;int vis[N*50][27];
string s,x;
void insert(const string &s,int id)
{
	int len=s.size()-1,now=1;
	for(int i=0;i<=len;i++)
	{
		int ch=s[i]-'a';
		if(!son[now][ch])
		{
			son[now][ch]=++cnt;
			vis[now][ch]=id;
			num[now][ch]++;
		}else
		{
			if(vis[now][ch]!=id)num[now][ch]++,vis[now][ch]=id;
		}
		
		now=son[now][ch];
	}
}
int query(const string &s)
{
	int len=s.size()-1,now=1;
	int ans=0;
	for(int i=0;i<=len;i++)
	{
		int ch=s[i]-'a';
		if(!son[now][ch])
		{
			return 0;
		}
		ans=num[now][ch];
		now=son[now][ch];
	}
	return ans;	
}
int main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	freopen("mdz.in","r",stdin);
	freopen("mdz.out","w",stdout);	
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>s;
		int len=s.size()-1;
		for(int k=0;k<=len;k++)
		{
			string tmp=s.substr(k,len-k+1);
			insert(tmp,i);		
		}
	}
	cin>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>x;
		cout<<query(x)<<endl;
	}
	return 0;
}
/*

*/

D. 清理牛棚

用DP的話,我們設當前狀態為i,f[i]表示0~i所需的最短時間,我們需要和前面區間比較
這是我們可以用線段樹最佳化,維護m到e之間的最小值,這樣動態轉移方程為

\[f[i]=min(f[i],w_i+query(1,l_i-1,r_i)) \]

還有一個注意的點,最後答案右端點比e大的都要比較,quzuiyouzhi

點選檢視程式碼
#include <bits/stdc++.h>
#define ll long long
#define lid (rt<<1)
#define rid (rt<<1|1)
using namespace std;
const int mod = 86399,N=1e4+5;
int n,m,e;
ll sum;
struct ac
{
	int st,en,s;
}a[N];
int f[mod*4];
struct tree
{
	int l,r,w;
}st[mod*5];
void pushup(int rt)
{
	st[rt].w=min(st[lid].w,st[rid].w);
}
void buildtree(int rt,int l,int r)
{
	st[rt].l=l;st[rt].r=r;
	if(l==r)
	{
		st[rt].w=f[l];
		return;
	}
	int mid=(l+r)>>1;
	buildtree(lid,l,mid);
	buildtree(rid,mid+1,r);	
	pushup(rt);
}
void modify(int rt,int l,int r,int val)
{
	if(l<=st[rt].l&&st[rt].r<=r)
	{
		st[rt].w=val;
		return;
	}
	int mid=(st[rt].l+st[rt].r)>>1;
	if(l<=mid)modify(lid,l,r,val);
	if(r>mid)modify(rid,l,r,val);
	pushup(rt);
}
int query(int rt,int l,int r)
{
	if(l<=st[rt].l&&st[rt].r<=r)
	{
		return st[rt].w;
	}
	int mid=(st[rt].l+st[rt].r)>>1;
	int ans=INT_MAX;
	if(l<=mid)ans=min(query(lid,l,r),ans);
	if(r>mid)ans=min(query(rid,l,r),ans);	
	return ans;
}
bool cmp(ac a,ac b)
{
	return a.en<b.en;	
}

int main()
{	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
//	freopen("clean_ex.in","r",stdin);
	freopen("clean.in","r",stdin);
	freopen("clean.out","w",stdout);	
	cin>>n>>m>>e;
	memset(f,0x3f,sizeof(f));
//	for(int i=m;i<=e;i++)f[i]=INT_MAX;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i].st>>a[i].en>>a[i].s;
		sum+=a[i].s;
	}
	sort(a+1,a+1+n,cmp);	
	f[m]=0;
	
	buildtree(1,m,e);
	for(int i=1;i<=n;i++)
	{
//		int ch=a[i].en-a[i].st+1;
		f[a[i].en]=min(f[a[i].en],query(1,a[i].st-1,a[i].en)+a[i].s);
		modify(1,a[i].en,a[i].en,f[a[i].en]);
		if(a[i].en>=e)
		{
			if(f[a[i].en]>sum)cout<<-1;
			else cout<<f[a[i].en];
			return 0;
		}
//		for(int k=st;k<=i;k++)f[k]=min(f[i],f[k]);
	}

	return 0;
	
}
/*
3 0 4
0 2 3
3 4 2
0 0 1
*/

E. 歷史研究

  1. 開longlong
  2. 注意細節
  3. 要離散化
    先說分塊的做法,首先分塊,按塊預先處理處每個元素出現次數的字首和,然後預先處理處i~j塊之間的答案編號
    查詢時,我們用桶記錄出現次數與重要度的乘積,散塊暴力,整塊直接出答案(記的加上分塊中的),然後比較哪個最大即可
點選檢視程式碼
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N =1e5+5;
int n,q,sq,st[500],en[500],belong[N],tot,ans[500][500];
ll b[N],a[N],cnt[500][N];map <ll,int> mp;
void init()
{
	sq=sqrt(n);
	for(int i=1;i<=sq;i++)
	{
		st[i]=n/sq*(i-1)+1;
		en[i]=n/sq*i;
	}
	en[sq]=n;
	for(int i=1;i<=sq;i++)
	{
		for(int j=st[i];j<=en[i];j++)
		{
			belong[j]=i;
		}
	}
	for(int i=1;i<=sq;i++)
	{
		for(int j=1;j<=n;j++)cnt[i][j]=cnt[i-1][j];
		for(int j=st[i];j<=en[i];j++)
		{
			cnt[i][a[j]]++;
		}
	}
	ll res=0,id=0;
	for(int i=1;i<=sq;i++)
	{
		for(int j=i;j<=sq;j++)
		{
			ans[i][j]=ans[i][j-1];
			res=b[ans[i][j]]*(cnt[j][ans[i][j]]-cnt[i-1][ans[i][j]]);
			id=ans[i][j-1];
			for(int k=st[j];k<=en[j];k++)
			{
				int p=a[k];
				if(res<b[p]*(cnt[j][p]-cnt[i-1][p]))
				{
					res=b[p]*(cnt[j][p]-cnt[i-1][p]);
					id=p;
				}
			}
			ans[i][j]=id;
		}
	}	
}
ll tong[N];
ll query(int l,int r)
{
	ll Ans=0;
	if(belong[l]==belong[r])
	{
		for(int i=l;i<=r;i++)
		{
			tong[a[i]]+=b[a[i]];
			Ans=max(Ans,tong[a[i]]);
		}
		for(int i=l;i<=r;i++)tong[a[i]]=0;
	}else
	{
		int res=ans[belong[l]+1][belong[r]-1];
		for(int i=l;i<=en[belong[l]];i++)
		{
			if(!tong[a[i]]&&a[i]!=res)
			{
				tong[a[i]]+=b[a[i]]*(cnt[belong[r]-1][a[i]]-cnt[belong[l]][a[i]]);
			}
			tong[a[i]]+=b[a[i]];
			Ans=max(tong[a[i]],Ans);
		}	
		for(int i=st[belong[r]];i<=r;i++)
		{
			if(!tong[a[i]]&&a[i]!=res)
			{
				tong[a[i]]+=b[a[i]]*(cnt[belong[r]-1][a[i]]-cnt[belong[l]][a[i]]);
			}
			tong[a[i]]+=b[a[i]];
			Ans=max(tong[a[i]],Ans);
		}
		Ans=max(Ans,(tong[res]+(cnt[belong[r]-1][res]-cnt[belong[l]][res])*b[res]));
		for(int i=l;i<=en[belong[l]];i++)tong[a[i]]=0;
		for(int i=st[belong[r]];i<=r;i++)tong[a[i]]=0;	
		
	}
	return Ans;
}
int main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
//	freopen("lsyj_ex.in","r",stdin);
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);	
	cin>>n>>q;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		if(!mp[a[i]])
		{
			mp[a[i]]=++tot;
			b[tot]=a[i];
		}
		a[i]=mp[a[i]];
	}
//	for(int i=1;i<=n;i++)
//	{
//		cout<<a[i]<<" ";
//	}
//	cout<<endl;
	int l,r;
	init();
	for(int i=1;i<=q;i++)
	{
		cin>>l>>r;
		cout<<query(l,r)<<endl;
		
	}
	return 0;
	
}
/*
5 5
9 8 7 8 9
1 2
3 4
4 4
1 4
2 4
*/

相關文章