[机房测试]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 ;
}