【做题日记】

P3294 [SCOI2016]背单词
贪心+Trie+dfs

贪心:对于一个串和他的前缀子串,尽可能把前缀放在前面

把后缀反向插转化为为前缀 trie插一遍
并查集重构树dfs求子树大小
按规则求和

Code
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
const int N=500057;
int n,idx,val[N],tot,size[N],fa[N],id[N];
long long ans;
int ch[N][30];
char s[N];
vector<int>tree[N];
inline int find(int x)
{
	if(x==fa[x]) return x;
	return fa[x]=find(fa[x]);
}

inline void insert(char s[],int num)
{
	int p=0;
	for(int i=strlen(s)-1;i>=0;i--)
	{
		int u=s[i]-'a';
		if(!ch[p][u]) ch[p][u]=++idx;
		p=ch[p][u];
	}
	val[p]=num;
}
inline void remake(int now)
{
	
	for(int i=0;i<26;i++)
	{
		int ver=ch[now][i];
		if(!ver) continue;
	    if(!val[ver])
	    {
	    	fa[ver]=find(now);
		}
	    else
	    {
	    	tree[val[find(now)]].push_back(val[ver]);
		}
		remake(ver);
	}
}
bool cmp(int x,int y)
{
	return size[x]<size[y];
}
inline void make(int now)
{
	size[now]=1;
	for(int i=0;i<tree[now].size();i++)
	{
		make(tree[now][i]);
		size[now]+=size[tree[now][i]];
	}
	sort(tree[now].begin(),tree[now].end(),cmp);
}
inline void dfs(int now)
{
	id[now]=tot++;
	
	for(int i=0;i<tree[now].size();i++)
	{
		ans+=tot-id[now];
		dfs(tree[now][i]);
	}
	
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%s",s);
		insert(s,i);
	}
	for(int i=1;i<=idx;i++) fa[i]=i;
	remake(0);
	make(0);
	dfs(0);
	printf("%lld",ans);
	return 0;
}

P3065 [USACO12DEC]First! G
Trie+拓扑
对于每一个字符串,能不能通过改变字母表,来让其排在最前面。
存在前缀相同的串或者其他字符串,则建边跑topo,判断有没有环,有环则无解。
已经有前缀存在,直接跳过。

Code
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;

const int N=300007;
queue<int>q;
int val[N],ch[N][30],f,h[30],e[1000],ne[1001],ans[N],idxx,idx,in[30],n,cnt;
char s[30010][100];
bool vis[30][30];
inline void add(int a,int b)
{
	e[idxx]=b,ne[idxx]=h[a],h[a]=idxx++;
}

inline void insert(char s[])
{
	int p=0;
	for(int i=0;i<strlen(s);i++)
	{
		int u=s[i]-'a';
		if(!ch[p][u]) ch[p][u]=++idx;
		p=ch[p][u];
	}
	val[p]=1;
}
inline bool topo()
{
	while(q.size()) q.pop();
	for(int i=0;i<26;i++)
	{
		if(!in[i]) q.push(i);
	}
	while(q.size())
	{
		int t=q.front();q.pop();
		for(int i=h[t];~i;i=ne[i])
		{
			int ver=e[i];
			--in[ver];
			if(!in[ver])
			{
			    q.push(ver);	
			}	
			
		}
	}
	for(int i=0;i<26;i++)
	{
		if(in[i])
		{
			return 0;
		}
	}
	return 1;
}

inline void solve(char s[])
{
	int p=0;
	for(int i=0;i<strlen(s);i++)
	{
		int u=s[i]-'a';
		if(val[p])
		{
			f=1;
			return ;
		}
		for(int j=0;j<26;j++)
		{
			if(ch[p][j]&&j!=u&&!vis[u][j])
			{
				vis[u][j]=1;
				add(u,j);
				in[j]++;
			}
		}
		p=ch[p][u];
	}
}
inline void init()
{
	idxx=0;
	f=0;
	memset(h,-1,sizeof h);
	memset(ne,0,sizeof ne);
	memset(vis,0,sizeof vis);
	memset(in,0,sizeof in);
}
int main()
{
	cin>>n;
	
	for(int i=1;i<=n;i++)
	{
		scanf("%s",s[i]);
		insert(s[i]);
	}
	
	for(int i=1;i<=n;i++)
	{
		init();
		solve(s[i]);
		
		if(f) continue;
		if(topo()) ans[++cnt]=i;
	}
	printf("%d\n",cnt);
	for(int i=1;i<=cnt;i++)
	{
	    printf("%s\n",s[ans[i]]);	
	}
	return 0;
}

2022桂林M题
逆序对
2022四川省赛E题
枚举a,b min25筛求素数前缀和

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=998244353;
ll inv2=499122177ll;
ll inv4=748683265ll;
ll inv6=166374059ll;
const ll N=1e6;


ll ksm(ll t, ll k)
{
    ll res=1%mod;
    while (k)
    {
        if (k&1) res=res*t%mod;
        t=t*t%mod;
        k>>=1;
    }
    return res%mod;
}
ll cnt,n;
ll pre0[N+10],pre1[N+10],pre2[N+10],pre3[N+10];
ll prime[N+10];
bool vis[N+10];
inline void init()
{

	
	for(int i=2;i<=N;i++)
	{
		if(!vis[i])
		{
			prime[++cnt]=i;
			pre0[cnt]=(pre0[cnt-1]+1ll)%mod;
			pre1[cnt]=(pre1[cnt-1]+1ll*i%mod)%mod;
			pre2[cnt]=(pre2[cnt-1]+1ll*i*i%mod)%mod;
			pre3[cnt]=(pre3[cnt-1]+1ll*i*i%mod*i%mod)%mod;
		}
		for(int j=1;i*prime[j]<=N&&j<=cnt;j++)
		{
			vis[i*prime[j]]=true;
			if(i%prime[j]==0) break;
		}
		
	}
	
}
// 前n项自然幂数和
inline ll sum1(ll x)
{
	x%=mod;
	return (1ll+x)*x%mod*inv2%mod;
}
inline ll sum2(ll x)
{
	x%=mod;
	return (x*(x+1ll)%mod*(2ll*x%mod+1ll)%mod)%mod*inv6%mod;
}
inline ll sum3(ll x)
{
	x%=mod;
	return (x*x%mod*(x+1ll)%mod)%mod*(x+1ll)%mod*inv4%mod;
}


ll g0[N+10],g1[N+10],g2[N+10],g3[N+10];
ll w[N+10],tot,id1[N+10],id2[N+10];

void solve()
{
	init();
	ll sq=sqrt(n+0.5);
	
	for(ll l=1,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		w[++tot]=n/l;
		ll tmp=(n/l)%mod;
		
		g0[tot]=(tmp-1ll+mod)%mod;
		g1[tot]=(sum1(tmp)-1ll+mod)%mod;
		g2[tot]=(sum2(tmp)-1ll+mod)%mod;
		g3[tot]=(sum3(tmp)-1ll+mod)%mod;
		
		if(tmp<=sq) id1[n/l]=tot;
		else id2[r]=tot;
	}
	
	for(int i=1;i<=cnt;i++)
	{
		for(int j=1;j<=tot&&prime[i]*prime[i]<=w[j];j++)
		{
		    // 定位k
			int k;
			if(w[j]/prime[i]<=sq) k=id1[w[j]/prime[i]];
			else k=id2[n/(w[j]/prime[i])];
			
			// g(n)=g(n)-h(i)*(g(k)-pre[i-1])
				
			g0[j]=(g0[j]-(g0[k]-pre0[i-1]+mod)%mod+mod)%mod;
			g1[j]=(g1[j]-prime[i]*(g1[k]-pre1[i-1]+mod)%mod+mod)%mod;
			g2[j]=(g2[j]-prime[i]*prime[i]%mod*(g2[k]-pre2[i-1]+mod)%mod+mod)%mod;
			g3[j]=(g3[j]-(prime[i]*prime[i]%mod*prime[i])%mod*((g3[k]-pre3[i-1]+mod)%mod+mod))%mod;
		}
	}

	for(int i=1;i<=tot;i++)
	{
		//cout<<i<<" "<<g0[i]<<endl;
	}
	ll ans=0;
	for(int i=1;i<=cnt&&prime[i]*prime[i]*prime[i]<=n;i++)
	{
		for(int j=i+1;j<=cnt&&n/prime[i]/prime[j]>prime[j];j++)
		{
			// a=p1+p2   b=p3
			// (a+b)^3=a^3+b^3+3(a^2)b+3a(b^2);
			ll a=(prime[i]+prime[j])%mod;
			ll a2=ksm(a,2);
			ll a3=ksm(a,3);
			ll b=n/prime[i]/prime[j];
			// 定位k
			int k;
			if(b<=sq) k=id1[b];
			else k=id2[n/b];
			
			ans=(ans+(a3*(g0[k]-pre0[j]+mod)%mod)%mod)%mod;
			ans=(ans+(g3[k]-pre3[j]+mod)%mod)%mod;
			ans=(ans+(3ll*a2%mod*(g1[k]-pre1[j]+mod)%mod)%mod)%mod;
			ans=(ans+(3ll*a%mod*(g2[k]-pre2[j]+mod)%mod)%mod)%mod;
	
		}
	}
	printf("%lld",ans);
}

int main()
{
	scanf("%lld",&n);
	solve();
	return 0;
}
posted @ 2022-10-31 13:56  watasky  阅读(26)  评论(0编辑  收藏  举报