• 【学习笔记】Public NOIP Round #3 简要题解


    A.移除石子

    模拟题。从左上角开始处理,讨论几种情况即可。

    复杂度 O ( T n log ⁡ n ) O(Tn\log n) O(Tnlogn)

    #include
    #define ll long long
    #define pb push_back
    #define fi first
    #define se second
    using namespace std;
    int T,n,lsh[3005],X[3005],Y[3005],cnt;
    deque<int>v[3005];
    int get(int x){return lower_bound(lsh+1,lsh+1+cnt,x)-lsh;}
    void print(pair<int,int>x,pair<int,int>y){
    	pair<int,int>le=make_pair(max(x.fi,y.fi),max(x.se,y.se));int d=max(abs(x.fi-y.fi),abs(x.se-y.se));
    	cout<<le.fi-d<<' '<<le.se-d<<' '<<le.fi<<' '<<le.se<<"\n";
    }
    int main(){
    	freopen("stone.in","r",stdin);
    	freopen("stone.out","w",stdout);
    	ios::sync_with_stdio(false);
    	cin.tie(0),cout.tie(0);
    	cin>>T;
    	while(T--){
    		cin>>n,cnt=0;for(int i=1;i<=n;i++)cin>>X[i]>>Y[i],lsh[++cnt]=X[i];
    		sort(lsh+1,lsh+1+cnt),cnt=unique(lsh+1,lsh+1+cnt)-lsh-1;
    		for(int i=1;i<=cnt;i++)v[i].clear();for(int i=1;i<=n;i++)v[get(X[i])].push_back(Y[i]);
    		cout<<"Yes"<<"\n";
    		pair<int,int>fuck=make_pair(0x3f3f3f3f,0x3f3f3f3f);
    		for(int i=1;i<=cnt;i++){
    			sort(v[i].begin(),v[i].end());
    			while(v[i].size()>1){
    				int x=v[i][0];v[i].pop_front();
    				int y=v[i][0];v[i].pop_front();
    				if(y<fuck.se){
    					int d=y-x;
    					cout<<lsh[i]-d<<' '<<x<<' '<<lsh[i]<<' '<<y<<"\n";
    				}
    				else if(y>fuck.se){
    					print(fuck,make_pair(lsh[i],x)),fuck=make_pair(0x3f3f3f3f,0x3f3f3f3f),v[i].push_front(y);					
    				}
    				else {
    					if(lsh[i]-fuck.fi>y-x)print(make_pair(lsh[i],x),make_pair(lsh[i],y));
    					else if(lsh[i]-fuck.fi<y-x)print(fuck,make_pair(lsh[i],y)),v[i].push_front(x);
    					else {
    						cout<<fuck.fi<<".5"<<' '<<x<<' '<<lsh[i]<<".5"<<' '<<y<<"\n";
    					}
    				}
    			}
    			if(v[i].size()){
    				if(fuck.fi==0x3f3f3f3f)fuck=make_pair(lsh[i],v[i][0]);
    				else {
    					print(fuck,make_pair(lsh[i],v[i][0])),fuck=make_pair(0x3f3f3f3f,0x3f3f3f3f);
    				}
    			}
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    B.抓内鬼

    这题没想到抽屉原理纯属脑抽

    首先把最短路图建出来,如果 1 → n 1\to n 1n直接相连的话直接把 { 1 , n } \{1,n\} {1,n}放到同一组即可。

    否则我们假设不存在长度为 3 3 3的最短路。设直接与 1 1 1相连的点的集合为 S S S,与 n n n相连的点的集合为 T T T,显然 S ∩ T = ∅ S\cap T=\empty ST=,大概是这个样子:

    请添加图片描述
    显然只需把 S S S或者 T T T全部分到同一组即可。而根据抽屉原理这是显然成立的。

    对于长度为 3 3 3的最短路,由于 1 , n 1,n 1,n分在了不同组,所以中间这个点总会与 1 1 1, n n n中的一个分在同一组。这样从 S S S T T T的任何路径都存在一条边满足两个端点被分在了同一组。

    时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

    #include
    #define ll long long
    #define pb push_back
    #define fi first
    #define se second
    using namespace std;
    int n,m,K,vis[200005],vis2[200005],a[200005],dis[200005],res[200005];
    vector<int>g[200005],vec;
    priority_queue<pair<int,int>>q;
    struct node{
    	int u,v;
    }e[200005];
    int main(){
    	freopen("catch.in","r",stdin);
    	freopen("catch.out","w",stdout);
    	ios::sync_with_stdio(false);
    	cin.tie(0),cout.tie(0);
    	cin>>n>>m>>K,memset(res,-1,sizeof res);
    	int l=K,r=n-K;
    	if(K==0){for(int i=1;i<=n;i++)cout<<"P";return 0;}
    	if(K==n){for(int i=1;i<=n;i++)cout<<"U";return 0;}
    	for(int i=1;i<=n;i++)cin>>a[i];
    	for(int i=1;i<=m;i++){
    		int u,v;cin>>u>>v,g[u].pb(v),g[v].pb(u),e[i]={u,v};
    	}
    	memset(dis,0x3f,sizeof dis),dis[1]=0,q.push(make_pair(0,1));
    	while(q.size()){
    		int u=q.top().se;q.pop();
    		if(vis[u])continue;vis[u]=1;
    		for(auto v:g[u]){
    			if(dis[u]+a[v]<dis[v])dis[v]=dis[u]+a[v],q.push(make_pair(-dis[v],v));
    		}
    	}for(auto u:g[n]){
    		if(dis[u]+a[n]==dis[n]){
    			vis2[u]=1,vec.pb(u);
    		}
    	}vec.pb(n);
    	if(vis2[1]){
    		if(l>=2)res[1]=res[n]=0,l-=2;
    		else if(r>=2)res[1]=res[n]=1,r-=2;
    		else {
    			cout<<"impossible";
    			return 0;
    		}
    	}
    	else {
    		if(l>=vec.size()){
    			for(auto x:vec)res[x]=0,l--;
    			res[1]=1,r--;
    		}
    		else if(r>=vec.size()){
    			for(auto x:vec)res[x]=1,r--;
    			res[1]=0,l--;
    		}
    		else if(l>=n-vec.size()){
    			for(int i=1;i<n;i++){
    				if(!vis2[i])res[i]=0,l--;
    			}res[n]=1,r--;
    		}
    		else {
    			for(int i=1;i<n;i++){
    				if(!vis2[i])res[i]=1,r--;
    			}res[n]=0,l--;
    		}
    	}
    	for(int i=1;i<=n;i++){
    		if(res[i]==-1){
    			if(l)res[i]=0,l--;else res[i]=1,r--;
    		}cout<<(res[i]?"P":"U");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    C.异或序列

    水题,但是我没看出来

    考虑最朴素的状态定义 ,设 d p i dp_i dpi表示以 i i i结尾的合法序列数目。那么 d p i = ∑ j < i d p j − ∑ j < i , p ( i ) = p ( j ) d p i ⊕ j dp_{i}=\sum_{jdpi=j<idpjj<i,p(i)=p(j)dpij 。其中 p ( i ) p(i) p(i)表示二进制下最高位的 1 1 1

    不难看出后面的式子可以前缀和优化,时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

    #include
    #define ll long long
    #define pb push_back
    #define fi first
    #define se second
    using namespace std;
    int n,mod;
    ll res,dp[1000005],sum[1000005];
    int main(){
    	freopen("xor.in","r",stdin);
    	freopen("xor.out","w",stdout);
    	ios::sync_with_stdio(false);
    	cin.tie(0),cout.tie(0);
    	cin>>n>>mod,dp[1]=sum[1]=res=1;
    	for(int i=2;i<=n;i++){
    		dp[i]=sum[i-1]+1;
    		int j=29;while(!(i>>j&1))j--;
    		for(int k=j-1;k>=0;k--){
    			if(i>>k&1){
    				dp[i]=(dp[i]-sum[(1<<(k+1))-1]+sum[(1<<k)-1])%mod;
    			}
    		}sum[i]=(sum[i-1]+dp[i])%mod;
    	}cout<<(sum[n]+mod)%mod;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    D.数圈圈

    分治好题。之前没遇到过这个想法。

    考虑对矩阵分治,每次选择长的一边割开,然后计算跨过 mid \text{mid} mid的圈的数目。

    在这里插入图片描述
    枚举 u u u, v v v,只需将左右方案数相乘。

    l u l_u lu表示向左延伸的最大长度, d i , u d_{i,u} di,u表示第 i i i列向下延伸的最大长度。

    要求 ∑ i = max ⁡ ( l u , l v ) m i d [ d i , u ≥ v ] \sum_{i=\max(l_u,l_v)}^{mid}[d_{i,u}\ge v] i=max(lu,lv)mid[di,uv]。不妨假设 l u > l v l_u>l_v lu>lv(后者再做一遍即可),原式变成了 ∑ i = l u m i d [ d i , u ≥ v ] \sum_{i=l_u}^{mid}[d_{i,u}\ge v] i=lumid[di,uv],只有 v v v一个变量,用桶维护即可。

    单层复杂度 O ( x y + x 2 ) = O ( x y ) O(xy+x^2)=O(xy) O(xy+x2)=O(xy) x ≤ y x\le y xy),即矩形面积。每一层复杂度 O ( n m ) O(nm) O(nm),总复杂度 O ( n m ( log ⁡ n + log ⁡ m ) ) O(nm(\log n+\log m)) O(nm(logn+logm))

    #include
    #define ll long long
    #define pb push_back
    #define fi first
    #define se second
    using namespace std;
    int n,m;
    int up[2005][2005],down[2005][2005],le[2005][2005],ri[2005][2005],siz[2005][2005],siz2[2005][2005],tong[2005];
    char s[2005][2005];
    ll solve(int X,int X2,int Y,int Y2){
    	if(X==X2||Y==Y2)return 0;
    	ll res=0;
    	if(X2-X>Y2-Y){
    		int mid=X+X2>>1;
    		res+=solve(X,mid,Y,Y2)+solve(mid+1,X2,Y,Y2);
    		for(int i=Y;i<=Y2;i++)for(int j=Y;j<=Y2;j++)siz[i][j]=siz2[i][j]=0;
    		for(int i=Y;i<=Y2;i++){
    			int l=max(X,up[mid][i]),tot=0;
    			for(int j=i+1;j<=Y2;j++)tong[j]=0;
    			for(int j=l;j<=mid;j++)tong[min(Y2,ri[j][i])]++;
    			for(int j=Y2;j>i;j--){
    				tot+=tong[j];if(max(X,up[mid][j])<=l)siz[i][j]+=tot;
    			}
    		}
    		for(int i=Y2;i>=Y;i--){
    			int l=max(X,up[mid][i]),tot=0;
    			for(int j=i-1;j>=Y;j--)tong[j]=0;
    			for(int j=l;j<=mid;j++)tong[max(Y,le[j][i])]++;
    			for(int j=Y;j<i;j++){
    				tot+=tong[j];if(max(X,up[mid][j])<l)siz[j][i]+=tot;
    			}
    		}
    		for(int i=Y;i<=Y2;i++){
    			int l=min(X2,down[mid+1][i]),tot=0;
    			for(int j=i+1;j<=Y2;j++)tong[j]=0;
    			for(int j=mid+1;j<=l;j++)tong[min(Y2,ri[j][i])]++;
    			for(int j=Y2;j>i;j--){
    				tot+=tong[j];if(min(X2,down[mid+1][j])>=l)siz2[i][j]+=tot;
    			}
    		}
    		for(int i=Y2;i>=Y;i--){
    			int l=min(X2,down[mid+1][i]),tot=0;
    			for(int j=i-1;j>=Y;j--)tong[j]=0;
    			for(int j=mid+1;j<=l;j++)tong[max(Y,le[j][i])]++;
    			for(int j=Y;j<i;j++){
    				tot+=tong[j];if(min(X2,down[mid+1][j])>l)siz2[j][i]+=tot; 
    			}
    		}
    		for(int i=Y;i<=Y2;i++)for(int j=i+1;j<=Y2;j++)if(s[mid][i]==s[mid+1][i]&&s[mid][j]==s[mid+1][j])res+=(ll)siz[i][j]*siz2[i][j];
    	}
    	else {
    		int mid=Y+Y2>>1;
    		res+=solve(X,X2,Y,mid)+solve(X,X2,mid+1,Y2);
    		for(int i=X;i<=X2;i++)for(int j=X;j<=X2;j++)siz[i][j]=siz2[i][j]=0;
    		for(int i=X;i<=X2;i++){
    			int l=max(Y,le[i][mid]),tot=0;
    			for(int j=i+1;j<=X2;j++)tong[j]=0;
    			for(int j=l;j<=mid;j++)tong[min(X2,down[i][j])]++;
    			for(int j=X2;j>i;j--){
    				tot+=tong[j];if(max(Y,le[j][mid])<=l)siz[i][j]+=tot;
    			}
    		}
    		for(int i=X2;i>=X;i--){
    			int l=max(Y,le[i][mid]),tot=0;
    			for(int j=i-1;j>=X;j--)tong[j]=0;
    			for(int j=l;j<=mid;j++)tong[max(X,up[i][j])]++;
    			for(int j=X;j<i;j++){
    				tot+=tong[j];if(max(Y,le[j][mid])<l)siz[j][i]+=tot;
    			}
    		}
    		for(int i=X;i<=X2;i++){
    			int l=min(Y2,ri[i][mid+1]),tot=0;
    			for(int j=i+1;j<=X2;j++)tong[j]=0;
    			for(int j=mid+1;j<=l;j++)tong[min(X2,down[i][j])]++;
    			for(int j=X2;j>i;j--){
    				tot+=tong[j];if(min(Y2,ri[j][mid+1])>=l)siz2[i][j]+=tot;
    			}
    		}
    		for(int i=X2;i>=X;i--){
    			int l=min(Y2,ri[i][mid+1]),tot=0;
    			for(int j=i-1;j>=X;j--)tong[j]=0;
    			for(int j=mid+1;j<=l;j++)tong[max(X,up[i][j])]++;
    			for(int j=X;j<i;j++){
    				tot+=tong[j];if(min(Y2,ri[j][mid+1])>l)siz2[j][i]+=tot;
    			}
    		}
    		for(int i=X;i<=X2;i++)for(int j=i+1;j<=X2;j++)if(s[i][mid]==s[i][mid+1]&&s[j][mid]==s[j][mid+1])res+=(ll)siz[i][j]*siz2[i][j];
    	}
    	return res;
    }
    int main(){
    	freopen("circle.in","r",stdin);
    	freopen("circle.out","w",stdout);
    	cin>>n>>m;for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			up[i][j]=(s[i-1][j]==s[i][j])?up[i-1][j]:i;
    			le[i][j]=(s[i][j-1]==s[i][j])?le[i][j-1]:j;
    		}
    	}
    	for(int i=n;i>=1;i--){
    		for(int j=m;j>=1;j--){
    			down[i][j]=(s[i+1][j]==s[i][j])?down[i+1][j]:i;
    			ri[i][j]=(s[i][j+1]==s[i][j])?ri[i][j+1]:j;
    		}
    	}
    	cout<<solve(1,n,1,m);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
  • 相关阅读:
    Redis系列10:HyperLogLog实现海量数据基数统计
    面经-框架-Spring Bean生命周期
    【中兴】web训练营~一文带你走进前端 | 百图制作
    Java数组的定义与使用
    电脑文件如何自动备份到网盘里?
    分享一下微信投票小游戏怎么做
    SpringBoot【访问静态资源、整合JSP、Thymeleaf】(三)-全面详解(学习总结---从入门到深化)
    基于STC12C5A60S2系列1T 8051单片的IIC总线器件模数芯片PCF8591实现模数转换应用
    【观察】数字化时代的咨询往何处走?软通咨询的思与行
    【Mysql学习笔记】- 2 多表查询
  • 原文地址:https://blog.csdn.net/cqbzlydd/article/details/127733441