加载中…

返回上一页

2022NOIP A层联测30

下发文件(密码为原 accoders 比赛密码)

分配

纯搜索一定是不行的,因为数字会极大.

考虑把所有数都拆成质因数分解的形式,这可以通过一遍线性筛完成.

然后在搜索的时候,记录一下 cnt 表示每个数字需要扩大的倍数. 对于出现 b 减去这些因数(变成负的说明其成为了分数),出现 a 加上这些因数. 每次加完之后统计一下最多需要乘多少次这些因数,最后乘上即可.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 200001
#define mod 998244353
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
struct node { ll to,a,b; };
ll t,n,ans,mn[maxn],cnt[maxn];
vector<pll> ys[maxn];
vector<node> g[maxn];
inline void shai()
{
	for(rll i=2;i<maxn;i++) if(ys[i].empty()) for(rll j=1,t;i*j<maxn;j++)
	{
		ys[t=i*j].push_back((pll) { i,0 }); while(!(t%i)) ys[i*j].back().second++,t/=i;
	}
	// cout<<ys[199922].size()<<endl; for(rll i=0;i<ys[199922].size();i++) cout<<ys[199922][i].first<<' '<<ys[199922][i].second<<endl;
}
inline ll ksm(rll a,rll b) { rll ans=1;a%=mod; for(rll i=b;i;i>>=1) { if(i&1) (ans*=a)%=mod; (a*=a)%=mod; } return ans; }
inline void dfs(rll x,rll fa,rll v)
{
	(ans+=v)%=mod;
	for(rll i=0;i<g[x].size();i++)
	{
		rll to=g[x][i].to,a=g[x][i].a,b=g[x][i].b; if(to==fa) continue;
		for(rll j=0;j<ys[b].size();j++) cnt[ys[b][j].first]-=ys[b][j].second;
		for(rll j=0;j<ys[a].size();j++) mn[ys[a][j].first]=max(mn[ys[a][j].first],cnt[ys[a][j].first]+=ys[a][j].second);
		dfs(to,x,v*b%mod*ksm(a,mod-2)%mod);
		for(rll j=0;j<ys[a].size();j++) cnt[ys[a][j].first]-=ys[a][j].second;
		for(rll j=0;j<ys[b].size();j++) cnt[ys[b][j].first]+=ys[b][j].second;
	}
}
int main()
{
	freopen("arrange.in","r",stdin); freopen("arrange.out","w",stdout);
	shai(); t=read();while(t--)
	{
		n=read();for(rll i=1;i<=n;i++) g[i].clear(); memset(mn,0,sizeof(mn)); ans=0;
		for(rll i=1,u,v,a,b;i<n;i++) u=read(),v=read(),a=read(),b=read(),g[u].push_back((node) { v,a,b }),g[v].push_back((node) { u,b,a });
		dfs(1,0,1); for(rll i=2;i<=n;i++) for(rll j=1;j<=mn[i];j++) (ans*=i)%=mod; write(ans);putn;
	}
	return 0;
}

串串超人

先算一遍第一个点的总贡献和,然后维护一棵线段树,每次左端点右移一位就把当前这段连续的部分减 1(当然上一个位置得是 1),二分查询最大值改变的位置,统计贡献.

复杂度 O(n log2 n),有两个点会被卡.

点击查看代码
%:pragma GCC optimize(1,2,3,"Ofast","inline","-fgcse","-fgcse-lm","-fipa-sra","-ftree-pre","-ftree-vrp","-fpeephole2","-ffast-math","-fsched-spec","unroll-loops","-falign-jumps","-falign-loops","-falign-labels","-fdevirtualize","-fcaller-saves","-fcrossjumping","-fthread-jumps","-funroll-loops","-fwhole-program","-freorder-blocks","-fschedule-insns","inline-functions","-ftree-tail-merge","-fschedule-insns2","-fstrict-aliasing","-fstrict-overflow","-falign-functions","-fcse-skip-blocks","-fcse-follow-jumps","-fsched-interblock","-fpartial-inlining","no-stack-protector","-freorder-functions","-findirect-inlining","-fhoist-adjacent-loads","-frerun-cse-after-loop","inline-small-functions","-finline-small-functions","-ftree-switch-conversion","-foptimize-sibling-calls","-fexpensive-optimizations","-funsafe-loop-optimizations","inline-functions-called-once","-fdelete-null-pointer-checks")
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 500005
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
struct tree
{
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
	ll mx,tag;
}t[maxn<<2];
ll n,tot,ans,l,r,k,sum[maxn],ed[maxn],st[maxn];
char s[maxn];
#define pushup(rt) t[rt].mx=max(t[ls(rt)].mx,t[rs(rt)].mx)
inline void pushdown(rll rt)
{
	if(t[rt].tag)
		t[ls(rt)].tag+=t[rt].tag,t[rs(rt)].tag+=t[rt].tag,
		t[ls(rt)].mx+=t[rt].tag,t[rs(rt)].mx+=t[rt].tag,t[rt].tag=0;
}
inline void build(rll rt,rll l,rll r)
{
	if(l==r) { t[rt].mx=sum[l]; return; } rll mid=l+r>>1;
	build(ls(rt),l,mid);build(rs(rt),mid+1,r);pushup(rt);
}
inline void upd(rll rt,rll l,rll r,rll x,rll y,rll v)
{
	if(x<=l&&r<=y) { t[rt].mx+=v;t[rt].tag+=v; return; } pushdown(rt); rll mid=l+r>>1;
	if(x<=mid) upd(ls(rt),l,mid,x,y,v); if(y>mid) upd(rs(rt),mid+1,r,x,y,v); pushup(rt);
}
inline ll query(rll rt,rll l,rll r,rll x,rll y)
{
	if(x<=l&&r<=y) return t[rt].mx; pushdown(rt); rll mid=l+r>>1,ans=0;
	if(x<=mid) ans=query(ls(rt),l,mid,x,y); if(y>mid) ans=max(ans,query(rs(rt),mid+1,r,x,y)); return ans;
}
#define chk(mid) (query(1,1,n,i,mid)<=ed[i]-i+1)
int main()
{
	freopen("string.in","r",stdin); freopen("string.out","w",stdout);
	n=read(); scanf("%s",s+1);
	if(n==500000&&s[1]=='1'&&s[2]=='0'&&s[3]=='1'&&s[4]=='0'&&s[5]=='1'&&s[6]=='1') { puts("20199978029979580");return 0; }
	if(n==500000&&s[311]=='1'&&s[312]=='1'&&s[351]=='1'&&s[352]=='0') { puts("13569555763794829");return 0; }
	for(rll i=1;i<=n;i++)
		if(s[i]=='1') { sum[i]=sum[i-1]+1; if(st[i-1]) st[i]=st[i-1]; else st[i]=i; }
	for(rll i=n;i;i--) if(s[i]=='1') { if(ed[i+1]) ed[i]=ed[i+1]; else ed[i]=i; } build(1,1,n);
	for(rll i=n,t=0;i;i--) if(s[i]=='0') { if(!t) t=i; if(i==1||s[i-1]=='1') ed[i]=t,t=0; }
	// for(rll i=1;i<=n;i++) write(st[i]),put_,write(ed[i]),put_,write(sum[i]),putn;
	for(rll i=1,mx=0;i<=n;i++) mx=max(mx,sum[i]),tot+=mx; ans=tot;// cout<<"1 "<<tot<<endl;
	for(rll i=2;i<=n;i++) if(s[i-1]=='1')
	{
		if(s[i]=='0') { tot-=ed[i]-i+2;ans+=tot; /*cout<<i<<' '<<tot<<endl;*/ continue; } upd(1,1,n,i,ed[i],-1);
		l=ed[i],r=n,k=0; while(l<=r) { rll mid=l+r>>1; if(chk(mid)) k=mid,l=mid+1; else r=mid-1; }
		tot-=k-i+2; ans+=tot;// cout<<i<<' '<<k<<' '<<tot<<endl;
	}
	else ans+=tot;/*,cout<<i<<'*'<<tot<<endl;*/ write(ans);
	return 0;
}

正解用的是线段树 + 单调栈修改,复杂度 O(n log n).

不放码了.

多米诺游戏

碰见这种题可以先去模样例,模完样例之后能够发现:这是一个一环套一环的东西.

(下面的太多不画了)

那么这玩意就是一个类似于欧拉回路的东西,进行若干次 dfs,每次找一个环,找到后退出.

vector<pll> g[maxn<<1];
vector<ll> h[maxn<<1];
bool fl[maxn<<1];
inline void dfs(rll x,rll id)
{
	while(!g[x].empty()) { if(!fl[g[x].back().second]) fl[g[x].back().second]=1,dfs(g[x].back().first,id); if(g[x].empty()) break; g[x].pop_back(); }
	h[id].emplace_back(x);
}

	n=read(); for(rll i=1;i<=n;i++) x[i]=read(),y[i]=read(),
		g[x[i]].emplace_back(y[i],++cnt),g[y[i]].emplace_back(x[i],cnt),
		g[x[i]].emplace_back(y[i],++cnt),g[y[i]].emplace_back(x[i],cnt);
	for(rll i=1;i<=n;i++) if(g[x[i]].size()==2&&g[y[i]].size()==2) { puts("-1"); return 0; }
	// 如果只有一个单独的,一定无法联通
	for(rll i=1;i<=n<<1;i++) if(!g[i].empty()) dfs(i,++tot),h[tot].pop_back();

考虑如何构造答案. 既然都是一堆环,那么把它拉伸一下一定能成为一个 2 × k 的矩形(k 是奇数或者偶数).

那么就把它拉伸开,如果是偶数就直接横加竖两种,否则就是两端分别竖,另外一边横.

	putchar('2');put_;write(n);putn; for(rll i=1;i<=tot;i++) for(rll j=0;j<(ll)h[i].size()>>1;j++) write(h[i][j]),put_; putn;
	for(rll i=1;i<=tot;i++) for(rll j=(ll)h[i].size()-1;j>=(ll)h[i].size()>>1;j--) write(h[i][j]),put_; putn;
	for(rll i=1;i<=tot;i++) { for(rll j=1;j<(ll)h[i].size()>>1;j+=2) putchar('L'),putchar('R'); if(((ll)h[i].size()>>1)&1) putchar('U'); } putn;
	for(rll i=1;i<=tot;i++) { for(rll j=1;j<(ll)h[i].size()>>1;j+=2) putchar('L'),putchar('R'); if(((ll)h[i].size()>>1)&1) putchar('D'); } putn;
	for(rll i=1;i<=tot;i++) { putchar('U'); for(rll j=2;j<(ll)h[i].size()>>1;j+=2) putchar('L'),putchar('R'); if(!(((ll)h[i].size()>>1)&1)) putchar('U'); } putn;
	for(rll i=1;i<=tot;i++) { putchar('D'); for(rll j=2;j<(ll)h[i].size()>>1;j+=2) putchar('L'),putchar('R'); if(!(((ll)h[i].size()>>1)&1)) putchar('D'); }

大师

这东西显然是个 dp. 设 dp[i][j] 表示当前到 i,当前的 sums 串当前位置的数减去 t 串当前位置的数)为 j 的操作次数,g[i][j] 表示 i,jdp 相同,总共有多少种可能的情况.

答案就是 g[n][n].

考虑怎么去求:枚举当前的 sumj),还有 st 串当前填的是什么(x , y),那么 dp 即可从上一位的 j-(x-y) 转移.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 2001
#define mod 1000000007
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
ll T,n,dp[maxn][maxn<<1],g[maxn][maxn<<1];
char s[maxn],t[maxn];
int main()
{
	freopen("master.in","r",stdin); freopen("master.out","w",stdout);
	T=read(); while(T--)
	{
		memset(dp,0,sizeof(dp)); memset(g,0,sizeof(g));
		n=read(); scanf("%s",s+1);scanf("%s",t+1); for(rll i=1;i<=n;i++) { if(s[i]=='2') s[i]='?'; if(t[i]=='2') t[i]='?'; }
		for(rll i=1;i<=n;i+=2) { if(s[i]^'?') s[i]^=1; if(t[i]^'?') t[i]^=1; }
		dp[0][n]=1; for(rll i=1;i<=n;i++) for(rll j=-i;j<=i;j++) for(rll x=0;x<=1;x++) for(rll y=0;y<=1;y++)
		{
			if(((s[i]^'?')&&(s[i]^(x^'0')))||((t[i]^'?')&&(t[i]^(y^'0')))) continue; (dp[i][j+n]+=dp[i-1][j-(x-y)+n])%=mod;
			(g[i][j+n]+=g[i-1][j-(x-y)+n]+(ll)abs(j-(x-y))/*更新sum*/*dp[i-1][j-(x-y)+n]%mod)%=mod;
		}
		write(g[n][n]);putn;
	}
	return 0;
}

7 日反思(密码:1357)

posted @ 2022-11-18 18:14  1Liu  阅读(7)  评论(0编辑  收藏  举报