2019.05.18 【NOIP提高组】模拟 A 组

111 篇文章 0 订阅
76 篇文章 0 订阅

JZOJ 1764 游戏

分析

可以求出第一行的系数,再深搜解决,只能说深搜按照某种意义上是过不了的,但是由于这道题正解就是这样,所以也无可奈何


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define rr register
using namespace std;
struct rec{int x,y;}a[101];
int n,m,maxx,ans,now=1,flag,f[2][101],b[101];
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
bool cmp(rec a,rec b){return a.x>b.x||(a.x==b.x&&a.y<b.y);}
void dfs(int dep,int sum){
    if (ans<sum) return;
    if (dep>n){
        if (ans==sum) flag=1;
        return;
    }
    if (!f[now][dep]) {dfs(dep+1,sum); return;}
    rr int t=(ans-sum)/f[now][dep];
    t=t>maxx?maxx:t;
    for (rr int i=0;i<=t;++i){
        b[dep]=i; dfs(dep+1,sum+f[now][dep]*i);
        if (flag) return;
    }
}
signed main(){
    n=iut(); m=iut(); maxx=iut(); ans=iut();
    for (rr int i=1;i<=m;++i) a[i]=(rec){iut(),iut()};
    sort(a+1,a+1+m,cmp); f[now][1]=1;
    for (rr int i=2,k=1;i<=n;++i){
        for (rr int j=1;j<=i;++j) f[now^1][j]=f[now][j-1]+f[now][j];
        for (rr int j=1;j<=i;++j)
        if (n-i+1==a[k].x&&j==a[k].y)
            ++k,f[now^1][j]=0;
        now^=1;
    }
    dfs(1,0);
    if (!flag) printf("-1");
    else for (rr int i=1;i<=n;++i) printf("%d\n",b[i]);
    return 0;
}

JZOJ 1764 过河

分析

真的只是一个暴力+玄学???
暴力答案,用布尔数组判断该时刻是否可到达


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
using namespace std;
bool dp[2][1011]; int upp[1011],dow[1011];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans; 
}
inline void min(int &a,int b){if (a>b) a=b;}
signed main(){
	for (rr int t=iut();t;--t){
		rr int n=iut(),ans=1,flag=0;
		for (rr int i=1;i<=n;++i) upp[i]=iut(),dow[i]=iut();
		memset(dp,0,sizeof(dp));
		for (;ans<601;++ans){
			memset(dp[ans&1],0,sizeof(dp[ans&1]));
			dp[(ans&1)^1][0]=1;
			for (rr int i=1;i<=n;++i)
			if ((ans-1)%(upp[i]+dow[i])+1>upp[i]) dp[ans&1][i]=0;
			else for (rr int j=i<5?0:i-5;j<i+6;++j) dp[ans&1][i]|=dp[(ans&1)^1][j];
			flag=dp[ans&1][n]|dp[ans&1][n-2]|dp[ans&1][n-1]|dp[ans&1][n-3]|dp[ans&1][n-4];
			if (flag) break;
		}
		if (flag) printf("%d\n",ans+1); else printf("No\n");
	}
	return 0;
} 

JZOJ 4669 弄提纲

题目

问以 l l l r r r结尾的字符串的公共后缀中,有多少个是原串的前缀,以及公共后缀与原串前缀的最大公共长度


分析

可以思考 K M P KMP KMP中的失配数组也就是所谓的最大公共长度,那么可以考虑一个点的失配连接该点,从字符串开头跑一遍广搜,那么深度也就是有多少种公共前后缀的可能,最大公共长度也就是 l c a ( l , r ) lca(l,r) lca(l,r),考虑用求 l c a lca lca t a r j a n tarjan tarjan解决


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
using namespace std;
const int N=30011;
struct node{int y,next;}e[N],ee[200011]; char s[N];
int f[N],v[N],dep[N],ls[N],lls[N],ans[200011],fail[N],m,k=1,kk=1,len;
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
inline void dfs(int x){
    f[x]=x; v[x]=1;
    for (rr int i=ls[x];~i;i=e[i].next)
    if (!v[e[i].y]){
        dep[e[i].y]=dep[x]+1;
        dfs(e[i].y); f[e[i].y]=x;
    }
    for (rr int i=lls[x];~i;i=ee[i].next)
        if (v[ee[i].y]) ans[i]=ans[i^1]=getf(ee[i].y);
}
signed main(){
    memset(ls,-1,sizeof(ls));
    memset(lls,-1,sizeof(lls));
    rr char c=getchar();
    while (isalpha(c)) s[++len]=c,c=getchar();
    m=iut();
    for (rr int i=1;i<=m;++i){
        rr int x=iut(),y=iut();
        ee[++kk]=(node){y,lls[x]}; lls[x]=kk;
        ee[++kk]=(node){x,lls[y]}; lls[y]=kk;
    }
    for (rr int i=2,j=0;i<=len;++i){
        while (j&&s[i]!=s[j+1]) j=fail[j];
        fail[i]=(j+=(s[i]==s[j+1]));
    }
    for (rr int i=1;i<=len;++i)
        e[++k]=(node){i,ls[fail[i]]},ls[fail[i]]=k;
    dfs(0);
    for (rr int i=1;i<=m;++i)
        printf("%d %d\n",dep[ans[i<<1]],ans[i<<1]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值