[机房测试]10.22

[机房测试]10.22

ssw02两天在有原题的情况下才370分,ssw02心态崩了

欢迎转载ssw02的博客:https://www.cnblogs.com/ssw02/p/11719011.html


入阵曲

题目传送门

暴力n^4做法可以得 N小于80 的分,可以得到55-65分不等,再加上各种特殊数据(背包,暴力枚举长度为2的。。。)可以得到80分。

这道题,考虑到任意一行的前缀和在 mod k 意义下如果相同,那么就会出现符合的序列。注意mod k 后为 0 的值。在之前再放一个0即可。统计个数就是 cnti/2 即可。

然后N^2枚举上下边界,在 O(N) 处理即可 。

#include<bits/stdc++.h>
using namespace std ; 
const  int  MAXN = 405 ;
#define ll long long
inline ll read(){
	ll s = 0 ; char  g= getchar() ; while( g>'9'||g<'0')g=getchar() ; 
	while( g>='0'&&g<='9' )s=s*10+g-'0',g=getchar() ; return s ; 
}
ll a[MAXN][MAXN] , sum[MAXN][MAXN] , cnt[ 1000005 ] , N , M , K , b[MAXN] , ans ;
void  work( int h1 , int h2 ){
	cnt[ 0 ] = b[0] = 0 ;
	for( register int i = 1 ;  i <= M ; ++i )b[i] = ( sum[h1][i]-sum[h2-1][i] )%K , cnt[ b[i] ] = 0 ;
	for( register int i = 0 ;  i <= M ; ++i )cnt[ b[i] ]++ ;
	for( register int i = 1 ;  i <= M ; ++i ){
		if( cnt[ b[i] ] == -1 )continue ;
		ans += (ll) cnt[b[i]]*(cnt[b[i]]-1LL) / 2LL , cnt[ b[i] ] = -1 ; 
	}
}
void  prepare(){
	for( register int i = 1 ; i <= N ; ++i )
	   for( register int j = 1 ; j <= M ; ++j )
	       sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + a[i][j] ;  
}
int main(){
	freopen("rally.in","r",stdin);
	freopen("rally.out","w",stdout);
	N = read() , M = read() , K = read() ;
	for( register int i = 1 ; i <= N ; ++i )
	   for( register int j = 1 ; j <= M ; ++j )a[i][j] = read() ;
	prepare() ;
	for( register int i = 1 ; i <= N ; ++i )
	   for( register int j = 1 ; j <= i ; ++j )work( i , j ) ;
	cout<<ans ; 
	return 0 ;  
}

将军令

ssw02几个月前的博客了:https://www.cnblogs.com/ssw02/p/11301208.html

这道题也可以用树形DP写,具体参见:SHOI2015[侦查守卫]

星空

先想到差分,然后用异或的性质将这道题目简化为单点翻转。

考虑到我们每次只能同时消除两个1,用bfs找出消除没两个1的代价。

然后状压DP。

不知为何,ssw02只能改到60分。

#include<bits/stdc++.h>
using namespace std ; 
const  int  MAXN = 40005 ;
#define ll long long
inline int read(){
	int s = 0 ; char  g= getchar() ; while( g>'9'||g<'0')g=getchar() ; 
	while( g>='0'&&g<='9' )s=s*10+g-'0',g=getchar() ; return s ; 
}
int  N , K , M  , m[65] , a[MAXN] , sum[MAXN] , cnt  ;
int  dis[20][20] , loc[20] , diss[MAXN] ;
bool vis[MAXN] ; 
ll dp[140000] ;
queue<int>q ; 
void  bfs( int x , int v ){
	for( register int i = 1 ; i <= N+1 ; ++i )diss[i] = (1<<30),vis[i]=false ;
	diss[x] = 0 ;while( !q.empty() )q.pop() ;
	q.push(x) ; vis[x] = true ; 
	while( !q.empty() ){
		int u = q.front() ; q.pop() ; 
		for( int i = 1 ; i <= M ; ++i ){
			int to = u + m[i] ;//if( to == N+1 )cout<<u<<" "<<m[i] <<" "<<diss[2] <<endl;
			if( to > N+1 )break ;
			if( vis[to] )continue ;
			diss[to] = diss[u] + 1 , vis[to] = true ;
			q.push( to ) ; 
		}
	}
	diss[x] = (1<<30) ;
	for( register int i = 1 ; i <= cnt ; ++i )
	    dis[v][i] = dis[i][v] = min( min( diss[ loc[i] ] , dis[v][i] ) , dis[i][v] ) ;
	//for( int i = 1 ; i <= N ; ++i )cout<<diss[i]<<" " ;cout<<endl ;
} 
void  prepare(){
	for( register int i = 0 ; i <= 19 ; ++i )
	    for( register int j = 0 ; j <= 19 ; ++j )dis[i][j] = (1<<30) ;
	for( register int i = 1 ; i <= N+1 ; ++i ){
		sum[i] = a[i-1]^a[i] ; if( sum[i] )loc[ ++cnt ] = i ;
	}
	//loc[ ++cnt ] = N+1  ;
}
void  work(){
	memset( dp , 60 , sizeof(dp) ) ; dp[0] = 0 ;
	for( int i = 0 , t = (1<<cnt)-1 ; i < t ; ++i ){
		int  fir = -1 ;
		for( int j = 0 ; j < cnt ; ++j )
		    if( !(i>>j&1) ){fir=j;break;}
		for( int j=fir+1;j<cnt;++j)
		    if( !(i>>j&1) ){
		   	    int now = i ;
		   	    now |= (1<<fir) , now |= (1<<j) ;
		   	    dp[now] = min( dp[now] , dp[i] + dis[fir+1][j+1] ) ;
		    }
	}
}
int main(){
    //freopen("starlit.in","r",stdin);
	//freopen("starlit.out","w",stdout);
	N = read() , K = read() , M = read() ; int m1 ;
	for( int i = 0 ; i <= 40000 ; ++i )a[i] = 1 ;
	for( int i = 1 ; i <= K ; ++i )m1 = read() , a[m1]=0 ;
	for( int i = 1 ; i <= M ; ++i )m[i] = read() ;
	sort(m+1,m+M+1) ; prepare() ;
	for( int i = 1 ; i <= cnt ; ++i )bfs( loc[i] , i ) ; 
	/*for( int i = 1 ; i <= cnt-1 ; ++i ){
		for( int j = 1 ; j <= cnt ; ++j )cout<<dis[i][j]<<" " ;cout<<endl ;
	}*/
	work() ;
	cout<<dp[(1<<cnt)-1]<<endl ;
	return 0 ;
}
原文地址:https://www.cnblogs.com/ssw02/p/11719011.html