1. 程式人生 > 其它 >2021.9.28考試總結[NOIP模擬64]

2021.9.28考試總結[NOIP模擬64]

T1三元組 T2簡單的字串 T3環路 T4過河

T1 三元組

發現確定\(b,c\)的情況下,\(a\)的值域是連續的。確定\(b\)\(a+b\)的取值是\([1+b,b+b]\)。樹狀陣列維護對每個\(b\)可行的\(c\)

注意取模後取值可能跨越多次值域。

\(code:\)

T1
#include<bits/stdc++.h>
#define int long long
using namespace std;

namespace IO{
	int read(){
		char ch=getchar(); int x=0,f=1;
		while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return x*f;
	}
	void write(int x,char sp){
		char ch[20]; int len=0;
		if(x<0){ putchar('-'); x=~x+1; }
		do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
		for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
	}
	inline int max(int x,int y){ return x<y?y:x; }
	inline int min(int x,int y){ return x<y?x:y; }
	inline void swap(int& x,int& y){ x^=y^=x^=y; }
	inline void ckmax(int& x,int y){ x=x<y?y:x; }
	inline void ckmin(int& x,int y){ x=x<y?x:y; }
} using namespace IO;

const int NN=100010;
int T,n,k,dlt,ans,cnt[50];

namespace BIT{
	int c[NN];
	void insert(int pos,int x){
		if(!pos) return c[0]+=x,void();
		while(pos<=max(n,k)){
			c[pos]+=x;
			pos+=pos&-pos;
		}
	}
	int query(int pos){
		int res=c[0];
		if(pos<0) return 0;
		while(pos){
			res+=c[pos];
			pos-=pos&-pos;
		}
		return res;
	}
} using namespace BIT;

signed main(){
	freopen("exclaim.in","r",stdin);
	freopen("exclaim.out","w",stdout);
	T=read();
	for(int t=1;t<=T;t++){
		n=read(); k=read();
		ans=0; memset(c,0,sizeof(c));
		for(int i=1;i<=n;i++) insert(i*i*i%k,1);
		for(int i=1;i<=n;i++){
			int l=(1+i*i)%k,r=(i+i*i)%k;
			if((i%k)==0) ans+=query(k-1)*(i/k);
			else if(l<=r) ans+=query(r)-query(l-1)+query(k-1)*(i/k);
			else ans+=query(k-1)-query(l-1)+query(r)+query(k-1)*(i/k);
			insert(i*i*i%k,-1);
		}
		printf("Case %lld: %lld\n",t,ans);
	}
	return 0;
}

T2 簡單的字串

\(n^3\)加剪枝。

\(code:\)

T2
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
namespace IO{
	int read(){
		char ch=getchar(); int x=0,f=1;
		while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return x*f;
	}
	void write(int x,char sp){
		char ch[20]; int len=0;
		if(x<0){ putchar('-'); x=~x+1; }
		do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
		for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
	}
	inline int max(int x,int y){ return x<y?y:x; }
	inline int min(int x,int y){ return x<y?x:y; }
	inline void swap(int& x,int& y){ x^=y^=x^=y; }
	inline void ckmax(int& x,int y){ x=x<y?y:x; }
	inline void ckmin(int& x,int y){ x=x<y?x:y; }
} using namespace IO;

const ULL base=6121;
const int NN=5010;
int n,ans,col[NN],sum[NN];
ULL pw[NN],has[NN];
inline ULL get(int l,int r){ return l>r?0:has[r]-has[l-1]*pw[r-l+1]; }

signed main(){
	freopen("s.in","r",stdin);
	freopen("s.out","w",stdout);
	n=read(); pw[0]=1;
	for(int i=1;i<=n;i++) sum[i]=sum[i-1]+(col[i]=read());
	for(int i=1;i<NN;i++) pw[i]=pw[i-1]*base;
	for(int i=1;i<=n;i++)
		has[i]=has[i-1]*base+(ULL)col[i];
	for(int r=2;r<=n;r++) for(int l=1;l<r;l++) if((r-l)&1){
		int mid=l+r>>1;
		if(sum[mid]-sum[l-1]!=sum[r]-sum[mid]) continue;
		ULL s2=get(mid+1,r);
		for(int b=l;b<=mid;b++){
			ULL s1=get(b,mid)*pw[b-l]+get(l,b-1);
			if(s1==s2){ ++ans; break; }
		}
	}
	write(ans,'\n');
	return 0;
}

T3 環路

鄰接矩陣的連續冪次和。

由於只需求主對角線的和,開兩倍的矩陣可以統計。

\(code:\)

T3


#include<bits/stdc++.h>
using namespace std;

namespace IO{
	int read(){
		char ch=getchar(); int x=0,f=1;
		while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return x*f;
	}
	void write(int x,char sp){
		char ch[20]; int len=0;
		if(x<0){ putchar('-'); x=~x+1; }
		do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
		for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
	}
	inline int max(int x,int y){ return x<y?y:x; }
	inline int min(int x,int y){ return x<y?x:y; }
	inline void swap(int& x,int& y){ x^=y^=x^=y; }
	inline void ckmax(int& x,int y){ x=x<y?y:x; }
	inline void ckmin(int& x,int y){ x=x<y?x:y; }
} using namespace IO;

const int NN=110,MM=NN<<1;
int n,m,k,ans;
char O[NN];

namespace matrix{
	int ext;
	struct mat{
		int s[MM][MM];
		void clr(){ memset(s,0,sizeof(s)); }
		void pre(){ clr(); for(int i=1;i<=ext;i++) s[i][i]=1; }
		mat operator*(const mat& a)const{
			mat res; res.clr();
			for(int i=1;i<=ext;i++)
				for(int k=1;k<=ext;k++)
					for(int j=1;j<=ext;j++)
						(res.s[i][j]+=1ll*s[i][k]*a.s[k][j]%m)%=m;
			return res;
		}
	}to;
	void qpow(int b){
		mat res; res.pre();
		while(b){
			if(b&1) res=res*to;
			to=to*to;
			b>>=1;
		}
		to=res;
	}
} using namespace matrix;

signed main(){
	freopen("tour.in","r",stdin);
	freopen("tour.out","w",stdout);
	n=read(); ext=n<<1;
	for(int i=1;i<=n;i++){
		scanf("%s",O+1);
		for(int j=1;j<=n;j++)
			to.s[i][j]=(O[j]=='Y');
		to.s[i][n+i]=to.s[n+i][n+i]=1;
	}
	k=read(); m=read();
	qpow(k);
	for(int i=1;i<=n;i++)
		(ans+=to.s[i][i+n])%=m;
	(ans+=m-n)%=m;
	write(ans,'\n');
	return 0;
}

T4 過河

發現方案肯定是先運所有關係的交集(豬王),然後每個關係運一個,之後把豬王運回來,再把其他豬運過去,最後把豬王運回去。

於是轉化為二分圖問題。發現豬王來回可以帶兩頭豬,問題轉化為刪兩個點有無方案令圖為二分圖。

列舉其中一個點,另一個點合法當且僅當它在所有奇環上,且它兒子的子樹內不同時存在奇環與偶環上的邊連向它的祖先鏈。建出搜尋樹,樹上差分奇環個數即可。

\(code:\)

T4
#include<bits/stdc++.h>
using namespace std;

namespace IO{
	int read(){
		char ch=getchar(); int x=0,f=1;
		while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
		while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
		return x*f;
	}
	void write(int x,char sp){
		char ch[20]; int len=0;
		if(x<0){ putchar('-'); x=~x+1; }
		do{ ch[len++]=(1<<4)+(1<<5)+x%10; x/=10; }while(x);
		for(int i=len-1;~i;--i) putchar(ch[i]); putchar(sp);
	}
	inline int max(int x,int y){ return x<y?y:x; }
	inline int min(int x,int y){ return x<y?x:y; }
	inline void swap(int& x,int& y){ x^=y^=x^=y; }
	inline void ckmax(int& x,int y){ x=x<y?y:x; }
	inline void ckmin(int& x,int y){ x=x<y?x:y; }
} using namespace IO;

const int NN=1010,MM=3010;
int t,n,m,ban,root,in[NN];
int idx,to[MM<<1],nex[MM<<1],head[NN],id[MM<<1];
bool Continue;
map<pair<int,int>,bool>mp;
struct relation{
	int a,b,c;
}p[MM];
inline void add(int a,int b,int c){
	if(mp[make_pair(a,b)]) return;
	mp[make_pair(a,b)]=mp[make_pair(b,a)]=1;
	to[++idx]=b; nex[idx]=head[a]; head[a]=idx; id[idx]=c;
	to[++idx]=a; nex[idx]=head[b]; head[b]=idx; id[idx]=c;
}

int sum,fa[NN],odd[NN],evo[NN],eve[NN],dep[NN],son[NN];
bool vis[MM],able[NN];
void clear(){
	sum=0;
	memset(odd,0,sizeof(odd));
	memset(evo,0,sizeof(evo));
	memset(eve,0,sizeof(eve));
	memset(dep,0,sizeof(dep));
	memset(vis,0,sizeof(vis));
	memset(able,0,sizeof(able));
}
void dfs(int s,int f,int d){
	dep[s]=d; fa[s]=f; able[s]=1;
	for(int i=head[s];i;i=nex[i]) if(!vis[id[i]]){
		int v=to[i]; vis[id[i]]=1;
		if(ban==v||root==v) continue;
		if(dep[v]){
			int tmp=dep[s]-dep[v]+1;
			if(tmp&1){
				++sum; ++odd[s]; --odd[fa[v]];
				++evo[s]; --evo[son[v]];
			}
			else ++eve[s], --eve[son[v]];
			continue;
		}
		son[s]=v;
		dfs(v,s,d+1);
		if(eve[v]&&evo[v]) able[s]=0;
		odd[s]+=odd[v];
		eve[s]+=eve[v];
		evo[s]+=evo[v];
	}
}

signed main(){
	freopen("river.in","r",stdin);
	freopen("river.out","w",stdout);
	t=read();
	while(t--){
		n=read(); m=read(); Continue=1; idx=root=0;
		memset(head,0,sizeof(head));
		memset(in,0,sizeof(in));
		mp.clear();
		for(int a,b,c,i=1;i<=m;i++){
			a=read(); b=read(); c=read();
			p[i].a=a; p[i].b=b; p[i].c=c;
			++in[a]; ++in[b]; ++in[c];
			if(in[a]==m||in[b]==m||in[c]==m) Continue=0;
		}
		if(n<4){ puts("no"); continue; }
		if(Continue){ puts("no"); continue; }
		for(int i=1;i<=n;i++) if(in[i]==m)
			if(!root) root=i;
			else Continue=1;
		if(Continue){ puts("yes"); continue; }
		for(int i=1;i<=m;i++)
			if(p[i].a==root) add(p[i].b,p[i].c,i);
			else if(p[i].b==root) add(p[i].a,p[i].c,i);
			else if(p[i].c==root) add(p[i].a,p[i].b,i);
		for(int k=1;k<=n;k++) if(root!=k){
			ban=k; clear();
			for(int i=1;i<=n;i++) if(i!=root&&i!=ban&&!dep[i])
				dfs(i,0,1);
			for(int i=1;i<=n;i++) if(i!=root&&i!=ban)
				if(able[i]&&odd[i]==sum) Continue=1;
		}
		puts(Continue?"yes":"no");
	}
	return 0;
}