noip28

东方专场?

T1

%%%WYZG

话说我考场上还想二维hash来着

考虑只记录弹幕中x的相对位置。

先选定弹幕一个点作为基准点(第一个出现的x即可),然后,枚举其他的x,记录下坐标差,然后去方格图中枚举,每找到一个x就去用坐标差计算出其他可能的x坐标,然后判断计算出的位置上是否有x,如果有,就消掉,下回不再枚举,没有,就说明不符合题目要求,输出No。

记得特判没有x的情况。

代码一些小细节可能没考虑到,但数据水,能过。

Code
#include<cstdio>
#define MAX 1010
#define re register
namespace OMA
{
   int t,n,m,a,b;
   struct node
   {
     int x,y;
   }pair[MAX*MAX];
   inline int read()
   {
     int s=0,w=1; char ch=getchar();
     while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
     while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
     return s*w;
   }
   signed main()
   {
     t = read();
     while(t--)
     {
       bool flag1 = false;
       char s1[MAX][MAX],s2[MAX][MAX];
       n = read(),m = read(),a = read(),b = read();
       for(re int i=1; i<=n; i++)
       {
         scanf("%s",s1[i]+1);
         if(!flag1)
         {
           for(re int j=1; j<=m; j++)
           { if(s1[i][j]=='x'){ flag1 = true; break ; } }
         }
       }
       bool flag2 = true;
       int cnt = 0,x1 = 0,y1 = 0;
       for(re int i=1; i<=a; i++)
       {
         scanf("%s",s2[i]+1);
         if(flag2)
         {
           for(re int j=1; j<=b; j++)
           {
             if(s2[i][j]=='x')
             { x1 = i,y1 = j,flag2 = false; break ; }
           }
         }
       }
       if((!x1||!y1)&&flag1)
       { printf("No\n"); continue ; }
       if((!x1||!y1)&&!flag1)
       { printf("Yes\n"); continue ; }
       for(re int i=1; i<=a; i++)
       {
         for(re int j=1; j<=b; j++)
         {
           if(s2[i][j]=='x')
           {
             if(i==x1&&j==y1)
             { continue ; }
             pair[++cnt] = (node){i-x1,j-y1};
           }
         }
       }
       flag1 = true;
       for(re int i=1; i<=n; i++)
       {
         for(re int j=1; j<=m; j++)
         {
           if(s1[i][j]=='x')
           {
             s1[i][j]=='.';
             for(re int k=1; k<=cnt; k++)
             {
               if(s1[i+pair[k].x][j+pair[k].y]!='x')
               { printf("No\n"); flag1 = false; break ; }
               s1[i+pair[k].x][j+pair[k].y] = '.';
             }
           }
           if(!flag1)
           { break ; }
         }
         if(!flag1)
         { break ; }
       }
       if(flag1)
       { printf("Yes\n"); }
     }
     return 0;
   }
}
signed main()
{ return OMA::main(); }

T2

又又又读题死亡,奇数位置指的是位置的编号,不是坐标大小。

小球进洞模型,然而我都不知道有这玩意

考虑dp,设 \(dp_{n,i}\) 表示给定 \(n\)时 ,\(x_{i}-x_{i-1}\) 的贡献,转移时枚举第一次选了那个球,它往那边滚了,直接转移 \(O(n^{3})\)

实际上我们并不需要枚举它往那边滚了,第一次选的球只有在 “i的旁边” 和 “不在i的旁边” 两种。所以复杂度 \(O(n^{2})\) 可过。

附80pts直接转移code

Code
#include<cstdio>
#define MAX 3100
#define re register
#define int long long
namespace OMA
{
   int n,x[MAX<<1],ans;
   int dp[MAX][MAX<<1];
   const int p = 998244353;
   inline int read()
   {
     int s=0,w=1; char ch=getchar();
     while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
     while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
     return s*w;
   }
   inline int quickpow(int a,int b)
   {
     int ans = 1;
     while(b)
     {
       if(b&1)
       { ans = ans*a%p; }
       a = a*a%p;
       b >>= 1;
     }
     return ans;
   }
   signed main()
   {
     n = read();
     for(re int i=1; i<=n*2+1; i++)
     { x[i] = read(); }
     for(re int i=1; i<=n; i++)
     {
       int inv1 = quickpow(i,p-2),inv2 = quickpow(i*2,p-2); 
       for(re int j=2; j<=2*i+1; j++)
       {
         int calc = (i*2-j+1)/2;
         if(j&1)
         { (dp[i][j] += dp[i-1][j-2]%p*inv2%p) %= p; }
         else
         { (dp[i][j] += dp[i-1][j]%p*inv2%p) %= p; }
         (dp[i][j] += ((dp[i-1][j]*calc%p*inv1%p+dp[i-1][j-1]*inv2%p)%p+(i-calc-1)*dp[i-1][j-2]%p*inv1%p+inv2%p)) %= p;
         /*for(re int k=1; k<=i; k++)
         {
           if(2*k>j)
           { (dp[i][j] += dp[i-1][j]*inv1%p) %= p; }
           else if(2*k==j-1)
           { (dp[i][j] += dp[i-1][j-1]*inv2%p+dp[i-1][j-2]*inv2%p+inv2) %= p; }
           else if(2*k<j)
           { (dp[i][j] += dp[i-1][j-2]*inv1%p) %= p; }
           else
           { (dp[i][j] += dp[i-1][j]*inv2%p+dp[i-1][j-1]*inv2%p+inv2) %= p; }
         }*/
       }
     }
     for(re int i=2; i<=n*2+1; i++)
     { (ans += dp[n][i]*(x[i]-x[i-1])%p) %= p; /*printf("%lld\n",dp[n][i]);*/ }
     printf("%lld\n",ans);
     return 0;
   }
}
signed main()
{ return OMA::main(); }

T3

注意到边的类型是单调变小的,考虑用两个并查集来维护边的种类,一个表示1类边,另一个表示1类边+2类边。

再维护需要经过3类边的点的个数,在维护修改时大力更新即可。

具体见代码。

初始化写锅调了好久QAQ

Code
#include<cstdio>
#define MAX 300010
#define re register
namespace OMA
{
	int n,m,num[MAX];
	struct graph
	{
		int next;
		int to;
		int w;
	}edge[MAX<<1];
	int cnt=1,head[MAX];
	inline void add(int u,int v,int w)
	{ edge[++cnt] = (graph){head[u],v,w},head[u] = cnt; }
	struct DSU
	{
		int fa[MAX],size[MAX];
		inline void start()
		{
			for(re int i=1; i<=n; i++)
			{ fa[i] = i,size[i] = 1; }
		}
		inline int find(int x)
		{ return x!=fa[x]?fa[x] = find(fa[x]):fa[x]; }
		inline void merge(int x,int y)
		{
			int r1 = find(x),r2 = find(y);
			if(r1!=r2)
			{ fa[r1] = r2,size[r2] += size[r1]; }
		}
	}dsu1,dsu2;
	int fa[MAX],sta[MAX];
	inline void dfs(int u,int die,int state)
	{
		fa[u] = die,sta[u] = state;
		for(re int i=head[u],v; i; i=edge[i].next)
		{
			v = edge[i].to;
			if(v!=die)
			{ dfs(v,u,edge[i].w); }
		}
	}
	struct stream
	{
		template<typename type>inline stream &operator >>(type &s)
		{
			int w=1; s=0; char ch=getchar();
			while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
			while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
			return s*=w,*this;
		}
	}cin;
	inline void swap(int &a,int &b)
	{ int t=a; a=b; b=t; }
	signed main()
	{
		cin >> n >> m;
		for(re int i=1,u,v,w; i<=n-1; i++)
		{ cin >> u >> v >> w; add(u,v,w),add(v,u,w); }
		dfs(1,0,0);
		dsu1.start(),dsu2.start();
		for(re int i=1; i<=n; i++)
		{
			if(sta[i]==1)
			{ dsu1.merge(i,fa[i]); }
			if(sta[i]!=3)
			{ dsu2.merge(i,fa[i]); }
		}
		for(re int i=1; i<=n; i++)
		{
			if(sta[i]==3)
			{ num[dsu1.find(fa[i])] += dsu2.size[i]; }
		}
		//for(re int i=1; i<=n; i++)
		//{ printf("sta[%d]=%d,num[%d]=%d %d %d\n",i,sta[i],i,num[i],dsu1.size[i],dsu2.size[i]); }
		for(re int i=1,a,b,s,t; i<=m; i++)
		{
			cin >> a >> b >> s >> t;
			if(fa[a]==b)
			{ swap(a,b); }
			if(sta[b]==2)
			{
				num[dsu1.find(a)] += num[b];
				dsu1.merge(b,a);
			}
			if(sta[b]==3)
			{
				num[dsu1.find(a)] -= dsu2.size[b];
				num[dsu1.find(fa[dsu2.find(a)])] += dsu2.size[b];
				dsu2.merge(b,a);
			}
			if(sta[b]!=1)
			{ sta[b]--; }
			bool flag = false;
			if(dsu2.find(s)==dsu2.find(t))
			{ flag = true; }
			if(dsu1.find(s)==dsu1.find(fa[dsu2.find(t)]))
			{ flag = true; }
			if(dsu2.find(fa[dsu1.find(s)])==dsu2.find(t))
			{ flag = true; }
			int ans = num[dsu1.find(s)]+dsu2.size[dsu2.find(s)];
			if(sta[dsu1.find(s)]==3)
			{ ans += dsu2.size[dsu2.find(fa[dsu1.find(s)])]; }
			printf("%d %d\n",flag?1:0,ans);
		}
		return 0;
	}
}
signed main()
{ return OMA::main(); }
posted @ 2021-07-31 06:30  -OMA-  阅读(80)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end