noip模擬3

ccjjxx發表於2024-11-03

這場好難。

A 網格

佇列裡的結構體陣列開大了導致 RE。。。

正解很簡潔,對於現在有的字串,新增一個數字或符號的轉移是相對固定的:

新增一個數字,如果前一位是運算子,那麼久新加一個數字,否則,讓現在的數字乘以 10 加上它;

新增運算子同理。

點選檢視程式碼
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e3+1,mod=998244353;
int n,m;
char s[N][N];
int dp1[N][N],dp2[N][N],dp3[N][N],dp4[N][N];
signed main()
{
    freopen("grid.in","r",stdin);
    freopen("grid.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
    dp2[1][0]=1,dp4[1][0]=1;
    for(int i=1;i<=n;i++)
	{
        for(int j=1;j<=m;j++)
		{
            dp4[i][j]=(dp4[i-1][j]+dp4[i][j-1])%mod,dp1[i][j]=(dp1[i-1][j]+dp1[i][j-1])%mod;
            dp2[i][j]=(dp2[i-1][j]+dp2[i][j-1])%mod,dp3[i][j]=(dp3[i-1][j]+dp3[i][j-1])%mod;
            if(s[i][j]=='+')dp1[i][j]=(dp1[i][j]+dp3[i][j])%mod,dp2[i][j]=dp4[i][j],dp3[i][j]=0;
			else if(s[i][j]=='*') dp2[i][j]=dp3[i][j],dp3[i][j]=0;
			else dp3[i][j]=(dp3[i][j]*10+(s[i][j]-'0')*dp2[i][j])%mod;
        }
    }
    printf("%lld",(dp1[n][m]+dp3[n][m])%mod);
    return 0;
}

B 矩形

太可惜了,考場上寫出來 \(O(n^2 \log n)\) 做法但是 RE,敲的不對。

寫對了有 \(64\) 分。

正解和我的思路很相似,但是存的東西不同。要存點的相對位置,看有多少組點可以上下匹配,然後再乘上係數。

需要離散化。

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
const int M=500;
#define ll long long
#define ull unsigned long long
int n;
ll ans;
struct nd{
	int x,y,id;
	bool operator<(const nd &t){
		if(x!=t.x)return x<t.x;
		return y<t.y;
	}
}a[N];
vector<int> ve[N];
int siz[N];
int mxx,mnx=1e9,mxy,mny=1e9;
int id[N],cnt,B;
ull sta[N],tp;
ull t=998244353;
ull hashp(int x,int y){
	return t*x+y;
}
const ll SZ=1.8e6+3;
ll gx(int x,int y){
	int l=0,r=0;
	ll res=0;
	for(;r<siz[y];r++){
		while(ve[x][l]<ve[y][r]&&l<siz[x]-1)l++;
		if(ve[x][l]==ve[y][r])res++;
	}
	return res*(res-1)/2;
}
struct hash_map{
    struct data {
        ull u;
    	int v,nex;
    }e[SZ<<1];
	int h[SZ],cnt;
	int hash(ull u){return u%SZ;}
	int &operator[](ull u) {
		ll hu = hash(u);
    	for (int i=h[hu];i;i=e[i].nex){
    		if(e[i].u==u)return e[i].v;
		}
   	 	return e[++cnt]=data{u,0,h[hu]},h[hu]=cnt,e[cnt].v;
  	}
	void clear(){
		cnt=0;
    	memset(h,0,sizeof(h));
	}
}mp;
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	#ifndef LOCAL
	freopen("rect.in","r",stdin);
	freopen("rect.out","w",stdout);
	#endif
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i].x>>a[i].y;
		a[i].id=i;
	}
	sort(a+1,a+n+1);
	int tmp=500;
	B=max(1,tmp);
	for(int i=1;i<=n;i++){
		if(a[i].x!=a[i-1].x){
			cnt++;
		}
		id[i]=cnt;
		ve[cnt].push_back(a[i].y);
	}
	for(int i=1;i<=cnt;i++){
		siz[i]=ve[i].size();
	}
	for(int i=1;i<=cnt;i++){
		if(siz[i]<=B){
			for(int j=0;j<siz[i];j++){
				for(int k=j+1;k<siz[i];k++){
					ull nowh=hashp(ve[i][j],ve[i][k]);
					ll val=mp[nowh];
					ans+=val;
					sta[++tp]=nowh;
				}
			}
			while(tp)mp[sta[tp--]]++;
		}
		else{
			for(int j=1;j<=cnt;j++){
				if((siz[j]>B&&j<i)||j==i)continue;
				ans+=gx(i,j);
			}
		}
	}
	cout<<ans;
	return 0;
}

C 集合

不可做。

D 倒水

\(52\) 分的 dp+性質:

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n;
const int N=1e5+4;
int a[N],p[N];
int calc[N];
int cnt=0;
const int mod=998244353;
int ppow(int a,int b)
{
	int res=1;
	while(b)
	{
		if(b&1) res=(res*a)%mod;
		a=(a*a)%mod,b>>=1;
	}return res;
}
void dfs(int x)
{
	if(x==n+1)
	{
		++cnt;cnt%=mod;
		for(int i=1;i<=n;i++) calc[i]+=p[i];
		return ;
	}
	for(int i=1;i<=n;i++)
	{
		if(i==x) continue;
		int tmp=min(a[i]-p[i],p[x]);
		p[i]+=tmp,p[x]-=tmp;
		dfs(x+1);
		p[i]-=tmp,p[x]+=tmp;
	}
}
int q[N];
int ans[N],dp[401][401];
signed main()
{
	freopen("bottle.in","r",stdin);
	freopen("bottle.out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n;
	bool _=1;
	for(int i=1;i<=n;i++) cin>>a[i],_&=(a[i]==1);
	if(_)
	{
		int inv=ppow(n-1,mod-2);
		int pos=1;
		p[1]=1;
		for(int i=2;i<=n;i++)
		{
			p[i]=pos*inv%mod,pos=(pos+p[i])%mod;
		}
		pos=p[n],q[n]=0;
		for(int i=n-1;i>=1;i--)
		{
			q[i]=pos*inv%mod,pos=(pos+p[i])%mod;
		}
		for(int i=1;i<=n;i++) cout<<q[i]<<"\n";
		return 0;
	}
	if(n<=8)
	{
		p[1]=a[1];
		dfs(1);
		const int inv=ppow(cnt,mod-2);
		for(int i=1;i<=n;i++) calc[i]=(calc[i]*inv)%mod,cout<<calc[i]<<"\n";
		return 0;
	}
	int inv=ppow(n-1,mod-2);
	dp[1][a[1]]=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=a[i];j++)
		{
			int p=inv*dp[i][j]%mod;
			for(int k=1;k<i;k++)
			{
				int v=min(j,a[k]);
				ans[i]+=p*(j-v),ans[i]%=mod;
				ans[k]+=p*v,ans[k]%=mod;
			}
			for(int k=i+1;k<=n;k++)
			{
				int v=min(j,a[k]);
				ans[i]+=p*(j-v),ans[i]%=mod;
				dp[k][v]+=inv*dp[i][j],dp[k][v]%=mod;
			}
		}
	}
	for(int i=1;i<=n;i++) cout<<ans[i]<<"\n";
	return 0;
}