6.29集训--集训模拟赛3

总结

今天集齐了四种颜色



这一次真是水翻了,除去第一题送分题,后三道题只拿了50分
开考后完全不在状态,最后的一个半小时一点代码都没有写出来

A、李时珍的皮肤衣




分析

\(n\)的数据最大达到了\(10^{10}\),显然是一道结论题
枚举几组样例可以发现,最终的答案为\(2^{n-1}+1\)\(n\)取模
其实就是相当于二进制下的进位
因为\(n\)很大,所以要用快速幂

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;
ll ksm(ll now,ll fa){
    ll xz=now;
    ll ans=1;
    while(fa){
        if(fa&1){
            ans*=xz;
            ans=ans%n;
        }
        fa=(fa>>1);
        xz=xz*xz%n;
    }
    return ans%n;
}
int main(){
    scanf("%lld",&n);
    printf("%lld\n",(ksm(2,n-1)+1)%n);
    return 0;
}

B、马大嘴的废话




分析

如果直接暴力枚举的话可以得到60分
然而暴力写挂了
这道题的最优解要用到AC自动机,但是AC自动机并没有学
林大佬用哈希表过了这道题,但模数比较难取,而且不用c++11会T
其实这一道题可以用Tire树维护

60代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=20005;
char s[maxn][25];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",s[i]);
    }
    int m;
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        char a[25];
        scanf("%s",a);
        int ans=0;
        int now=strlen(a);
        int be=0;
        for(int j=1;j<=n;j++){
           if(strstr(s[j],a)!=NULL) ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}

哈希表代码(林大佬)

#include<cstdio>
#include<algorithm>
#include<unordered_map>
#include<string>
#include<cstring>
#include<vector>
using namespace std;

#define ll long long

const ll mod1=2e17+19260817;
const int maxch=43;
const int maxn=2e1+1;

unordered_map<ll,int> mapp1;
vector<ll> s1;
unordered_map<ll,bool> vis1;
char a[maxn];
int n;

void solve1(int l,int r)
{
	ll ans=0,now=1ll;
	for(int i=l;i<=r;i++)
	{
		ans+=now*(a[i]-'a'+1)%mod1,ans%=mod1;
		now*=(ll)maxch,now%=mod1;
	}
	if(vis1[ans]) return;
	else vis1[ans]=1,s1.push_back(ans),mapp1[ans]++;
}

int calc1()
{
	ll ans=0,now=1ll;
	for(int i=0;i<n;i++)
	{
		ans+=now*(a[i]-'a'+1)%mod1,ans%=mod1;
		now*=(ll)maxch,now%=mod1;
	}
	return mapp1[ans];
}

int main()
{
	int m;
	scanf("%d",&n);
	while(n--)
	{
		scanf("%s",a);
		m=strlen(a);
		for(int i=0;i<m;i++)
			for(int j=i;j<m;j++)
				solve1(i,j);
		for(int i=0;i<s1.size();i++) vis1[s1[i]]=0;
		s1.clear();
	}
	scanf("%d",&m);
	while(m--)
	{
		scanf("%s",a);
		n=strlen(a);
		printf("%d\n",calc1());
	}
	return 0;
}

Tire树代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
int tire[maxn][26],mark[maxn][26],cnt[maxn][26];
int n,m;
int tot=0;
char s[30];
char a[30];
void insert(int l,int r,int id){
	int now=0;
	int t;
	for(int i=l;i<=r;i++){
		t=s[i]-'a';
		if(tire[now][t]){
			if(id!=mark[now][t]){
			    cnt[now][t]++;
			    mark[now][t]=id;
			}
		}
		else {
			tire[now][t]=++tot;
			mark[now][t]=id;
			cnt[now][t]=1;
		}
		now=tire[now][t];
	}
}
int query(char a[]){
	int len=strlen(a);
	int now=0,ans=0;
	for(int i=0;i<len;i++){
		int t=a[i]-'a';
		if(tire[now][t]==0)return 0;
		ans=cnt[now][t];
		now=tire[now][t];
	}
	return ans;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>s;
		int len=strlen(s);
		for(int j=0;j<len;j++){
			insert(j,len-1,i);
		}
	}
	cin>>m;
	for(int i=1;i<=m;i++){
		cin>>a;
		cout<<query(a)<<'\n';
	}
	return 0;
}

C、SSY的队列



分析

这道题的正解要用哈希表,所以先讲一下部分分的解法
首先就是最简单的暴力枚举,求全排列,每次求出来之后判断是否合法,预计得分二十分
还有一种七十分的状压DP解法
我们设\(f[i][j]\)为当前排好队的人的状态为\(i\),并且队伍末尾的人为\(j\)时的方案数
所以有\(f[i][j]+=f[i^(1<<(j-1))][k];\)
其中\(abs(a[j]-a[k])%m!=0\)
\(i\&(1<<(j-1))!=0\)
\(i\&(1<<(k-1))!=0\)

20分暴力

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1234567891;
const int maxn=35;
ll a[maxn];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    ll m;
    scanf("%lld",&m);
    sort(a+1,a+1+n);
    ll ans=0;
    while(1){
        bool jud=0;
        for(int i=1;i<n;i++){
            if(abs(a[i]-a[i+1])%m==0){
                jud=1;
                break;
            }
        }
        if(jud==0) ans++;
        if(next_permutation(a+1,a+n+1)==0) break;
    }
    printf("%lld\n",ans%mod);
    return 0;
}

70分状压

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=23;
const ll mod=1234567891;
ll f[1<<maxn][maxn],a[maxn];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        f[1<<(i-1)][i]=1;
    }
    ll m;
    scanf("%lld",&m);
    int mmax=(1<<n)-1;
    for(int i=0;i<=mmax;i++){
        for(int j=1;j<=n;j++){
            for(int k=1;k<=n;k++){
                if(abs(a[j]-a[k])%m==0 || (i&(1<<(j-1))==0) || (i&(1<<(k-1))==0)) continue;
                f[i][j]+=f[i^(1<<(j-1))][k];
                f[i][j]%=mod;
            }
        }
    }
    ll ans=0;
    for(int i=1;i<=n;i++){
        ans+=f[mmax][i];
        ans%=mod;
    }
    printf("%lld\n",ans);
    return 0;
}

D、清理牛棚



分析

这道题的解法很多,有线性DP、线段树优化DP、单调栈优化DP、最短路

最短路解法

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e6+5;
struct asd{
    int from,to,next;
    ll val;
}b[maxn];
int head[maxn],tot=1;
void ad(int aa,int bb,ll cc){
    b[tot].from=aa;
    b[tot].to=bb;
    b[tot].val=cc;
    b[tot].next=head[aa];
    head[aa]=tot++;
}
struct jie{
    int num;
    ll jl;
    jie(int aa=0,ll bb=0){
        num=aa,jl=bb;
    }
    bool operator < (const jie& A) const{
        return jl>A.jl;
    }
};
ll dis[maxn];
bool vis[maxn];
priority_queue<jie> q;
void dij(int xx){
    memset(dis,0x3f,sizeof(dis));
    dis[xx]=0;
    q.push(jie(xx,0));
    while(!q.empty()){
        int now=q.top().num;
        q.pop();
        if(vis[now]) continue;
        vis[now]=1;
        for(int i=head[now];i!=-1;i=b[i].next){
            int u=b[i].to;
            if(dis[u]>dis[now]+b[i].val){
                dis[u]=dis[now]+b[i].val;
                q.push(jie(u,dis[u]));
            }
        }
    }
}
int main(){
    memset(head,-1,sizeof(head));
    int n,m,e;
    scanf("%d%d%d",&n,&m,&e);
    for(int i=1;i<=n;i++){
        int aa,bb;
        ll cc;
        scanf("%d%d%lld",&aa,&bb,&cc);
        ad(aa,bb+1,cc);
    }
    for(int i=m;i<e;i++){
        ad(i+1,i,0);
    }
    dij(m);
    if(dis[e+1]==0x3f3f3f3f3f3f3f3f){
        printf("-1\n");
        return 0;
    }
    printf("%lld\n",dis[e+1]);
    return 0;
}

线性DP解法

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100005;
ll f[maxn];
struct asd{
    int l,r;
    ll hd;
}b[maxn];
bool cmp(asd aa,asd bb){
    if(aa.r==bb.r) return aa.l<bb.l;
    return aa.r<bb.r;
}
int main(){
    memset(f,0x3f,sizeof(f));
    int n,m,e;
    scanf("%d%d%d",&n,&m,&e);
    for(int i=1;i<=n;i++){
        scanf("%d%d%lld",&b[i].l,&b[i].r,&b[i].hd);
    }
    sort(b+1,b+1+n,cmp);
    f[m]=0;
    ll ans=0x3f3f3f3f3f3f3f3f;
    for(int i=1;i<=n;i++){
        for(int j=b[i].l-1;j<b[i].r;j++){
            f[b[i].r]=min(f[b[i].r],f[j]+b[i].hd);
        }
        if(b[i].l<=e && b[i].r>=e) ans=min(ans,f[b[i].r]);
    }
    if(ans==0x3f3f3f3f3f3f3f3f) printf("-1\n");
    else printf("%d\n",ans);
    return 0;
}

线段树优化DP

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

#define ll long long

const int maxe=9e4+1;
const int maxn=1e4+1;
const ll inf=0x3f3f3f3f3f3f3f3f;

struct Node
{
	int x,y,val;
}a[maxn];
ll mn[maxe<<2];

void dfs(int x,int l,int r,int pos,ll val)
{
	if(l==r)
	{
		mn[x]=min(mn[x],val);
		return;
	}
	int mid=l+r>>1;
	if(pos<=mid) dfs(x<<1,l,mid,pos,val);
	else dfs(x<<1|1,mid+1,r,pos,val);
	mn[x]=min(mn[x<<1],mn[x<<1|1]);
}

ll query(int x,int l,int r,int left,int right)
{
	if(l>=left&&r<=right) return mn[x];
	int mid=l+r>>1;
	ll ans=inf;
	if(left<=mid) ans=min(ans,query(x<<1,l,mid,left,right));
	if(right>mid) ans=min(ans,query(x<<1|1,mid+1,r,left,right));
	return ans;
}

int cmp(const Node &x,const Node &y)
{
	return x.y<y.y;
}

int main()
{
	int n,m,e;
	scanf("%d%d%d",&n,&m,&e);
	m-=2;e-=m;
	memset(mn,0x3f,sizeof(mn));
	for(int i=0;i<n;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].val),a[i].x-=m,a[i].y-=m;
	dfs(1,1,e,1,0);
	sort(a,a+n,cmp);
	for(int i=0;i<n;i++)
	{
		ll now=query(1,1,e,a[i].x-1,a[i].y-1);
		if(now!=inf) dfs(1,1,e,a[i].y,now+(ll)a[i].val);
	}
	ll ans=query(1,1,e,e,e);
	printf("%lld",ans==inf?-1:ans);
	return 0;
}
posted @ 2020-06-29 16:51  liuchanglc  阅读(181)  评论(0编辑  收藏  举报