2019.11.06【NOIP提高組】模擬 B 組

JZOJ 3843 尋找羔羊

題目

給定一個由小寫字母組成的字符串,尋找包含agnus的子串的個數。注意:當且僅當兩個子串的起始位置和終點不同時,這兩個子串屬於不同的子串。


分析

若找到一個羔羊單詞,那麼計算左右可擴展的範圍,乘起來再求和即可


代碼

#include <cstdio>
#include <cstring>
#define rr register
using namespace std;
char s[30011]; int n,ans;
signed main(){
	scanf("%s",s+1);
	n=strlen(s+1); rr int st=0;
	for (rr int i=5;i<=n;++i)
	if (s[i-4]=='a'&&s[i-3]=='g'&&s[i-2]=='n'&&s[i-1]=='u'&&s[i]=='s'){
		ans+=(n-i+1)*(i-4-st);
		st=i-4;
	}
	return !printf("%d",ans);
}

JZOJ 3844 統計損失

題目

求一棵樹上任意兩點(可以相同)間的邊權之積的和


分析

dp[x]dp[x]表示以xx爲根的子樹所形成一端爲xx的簡單路徑的邊權之積的和,那麼
dp[x]=a[x]+isondp[i]a[x]dp[x]=a[x]+\sum_{i\in son}dp[i]*a[x]
f[x]f[x]表示以xx爲根的子樹所形成的兩端都不爲xx的簡單路徑的邊權之積的和,那麼
f[x]=isondp[son](i)dp[i]a[x]f[x]=\sum_{i\in son}dp[son](\neq i)*dp[i]*a[x]
把兩者加起來就是答案


代碼

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int mod=10086,N=100011;
struct node{int y,next;}e[N<<1];
int dp[N],f[N],ls[N],a[N],n,k=1;
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 signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline void dfs(int x,int fa){
	rr int sum=0;
	for (rr int i=ls[x];i;i=e[i].next)
	if (e[i].y!=fa){
		dfs(e[i].y,x); rr int now=a[x]*dp[e[i].y]%mod;
		f[x]=mo(f[x],sum*now%mod);
		dp[x]=mo(dp[x],now);
		sum=mo(sum,dp[e[i].y]);
	}
	dp[x]=mo(dp[x],a[x]); 
}
signed main(){
	n=iut();
	for (rr int i=1;i<=n;++i) a[i]=iut()%mod;
	for (rr int i=1;i<n;++i){
		rr int x=iut(),y=iut();
		e[++k]=(node){y,ls[x]},ls[x]=k,
		e[++k]=(node){x,ls[y]},ls[y]=k;
	}
	dfs(1,0); rr int ans=0;
	for (rr int i=1;i<=n;++i) ans=mo(ans,mo(dp[i],f[i]));
	return !printf("%d",ans);
}

JZOJ 3845 簡單題

題目

在一個無向圖中找到存在一條簡單路徑使1n1\sim n順次連接的仙人掌,問這個仙人掌的最大邊數


分析

首先有n1n-1條邊是必須的,設f[i]f[i]表示1i1\sim i所組成的仙人掌所能含的最大邊數,那麼f[i]=min(f[i1],f[maxlef[i]]+1)f[i]=min(f[i-1],f[maxlef[i]]+1)maxlefmaxlef表示某個右端點所擁有的邊中最大的左端點


代碼

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=100011;
int n,m,ans,dp[N],pre[N];
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 Mx(int &a,int b){a=a>b?a:b;}
signed main(){
	n=iut(); m=iut();
	for (rr int i=1;i<=m;++i){
		rr int x=iut(),y=iut();
		if (x>y) x^=y,y^=x,x^=y;
		if (x+1<y&&pre[y]<x) pre[y]=x;
	}
	for (rr int i=1;i<=n;++i){
	    dp[i]=dp[i-1];
	    if (pre[i]) Mx(dp[i],dp[pre[i]]+1);
    }
    return !printf("%d",dp[n]+n-1);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章