NOIP模拟 2017.10.4 总结
来源:互联网 发布:房贷利息抵扣个税算法 编辑:程序博客网 时间:2024/05/17 23:21
说在前面
Emmmmmm,每次好不容易想出来解法,实现上却总是各种疏忽,该拿的分拿不满,很气。
题目&&题解
T1
这个题好像是没有什么针对的数据结构的,但是其实可以用一个线段树就把这个题水了,因为字母一共只有26种,我们可以直接查询每种数字的个数,然后一段一段的区间修改。如果是升序,从A到Z依次赋值,降序就从Z到A,常数比较大但是可以加一些比如读优和register一样的玄学优化
可以卡过就对了嘛=w=
#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;int N , M ;char ss[100005] ;struct Node{ int cnt[26] , flag ; Node *ls , *rs ; Node(){ memset( cnt , 0 , sizeof( cnt ) ) ; } void pushdown( int lf , int rg ){ if( flag != -1 ){ int mid = ( lf + rg ) >> 1 ; for( register int i = 0 ; i < 26 ; i ++ ) ls->cnt[i] = rs->cnt[i] = 0 ; ls->cnt[ flag ] = ( mid - lf + 1 ) ; rs->cnt[ flag ] = ( rg - mid ) ; ls->flag = rs->flag = flag ; flag = -1 ; } } void updata(){ for( register int i = 0 ; i < 26 ; i ++ ) cnt[i] = ls->cnt[i] + rs->cnt[i] ; }}w[200005] , *root , *tw = w ;inline int read_(){ int rt = 0 ; char ch = getchar() ; while( ch < '0' || ch > '9' ) ch = getchar() ; while( ch >='0' && ch <='9' ) rt = (rt<<1) + (rt<<3) + ch - '0' , ch = getchar() ; return rt ;}Node *build( int lf , int rg ){ Node *nd = ++tw ; if( lf == rg ) nd->cnt[ ss[lf]-'a' ] = 1 ; else{ int mid = ( lf + rg ) >> 1 ; nd->ls = build( lf , mid ) ; nd->rs = build( mid+1 , rg ) ; nd->updata() ; nd->flag = -1 ; } return nd ;}void Modify( Node *nd , int lf , int rg , int L , int R , int delta ){ if( L <= lf && rg <= R ){ nd->flag = delta ; for( int i = 0 ; i < 26 ; i ++ ) nd->cnt[i] = 0 ; nd->cnt[delta] = ( rg - lf + 1 ) ; return ; } int mid = ( lf + rg ) >> 1 ; nd->pushdown( lf , rg ) ; if( L <= mid ) Modify( nd->ls , lf , mid , L , R , delta ) ; if( R > mid ) Modify( nd->rs , mid+1, rg , L , R , delta ) ; nd->updata() ;}Node Query( Node *nd , int lf , int rg , int L , int R ){ if( L <= lf && rg <= R ) return *nd ; else{ Node rt = Node() , tmp ; int mid = ( lf + rg ) >> 1 ; nd->pushdown( lf , rg ) ; if( L <= mid ){ tmp = Query( nd->ls , lf , mid , L , R ) ; for( register int i = 0 ; i < 26 ; i ++ ) rt.cnt[i] += tmp.cnt[i] ; } if( R > mid ){ tmp = Query( nd->rs , mid+1 , rg , L , R ) ; for( register int i = 0 ; i < 26 ; i ++ ) rt.cnt[i] += tmp.cnt[i] ; } return rt ; }}void print( Node *nd , int lf , int rg ){ if( lf == rg ){ for( int i = 0 ; i < 26 ; i ++ ) if( nd->cnt[i] ){ printf("%c" , i + 'a' ) ; return ; } } int mid = ( lf + rg ) >> 1 ; nd->pushdown( lf , rg ) ; print( nd->ls , lf , mid ) ; print( nd->rs , mid+1 , rg ) ;}void solve(){ for( register int i = 1 , x , L , R ; i <= M ; i ++ ){ L = read_() ; R = read_() ; x = read_() ; int st = L ; Node tmp = Query( root , 1 , N , L , R ) ; switch( x ){ case 1:{ for( register int j = 0 ; j < 26 ; j ++ ) if( tmp.cnt[j] ){ Modify( root , 1 , N , st , st + tmp.cnt[j] - 1 , j ) ; st += tmp.cnt[j] ; } break; } default:{ for( register int j = 25 ; j >= 0 ; j -- ) if( tmp.cnt[j] ){ Modify( root , 1 , N , st , st + tmp.cnt[j] - 1 , j ) ; st += tmp.cnt[j] ; } } } } print( root , 1 , N ) ;}int main(){ freopen( "string.in" , "r" , stdin ) ; freopen( "string.out", "w" , stdout) ; N = read_() ; M = read_() ; scanf( "%s" , ss + 1 ) ; root = build( 1 , N ) ; solve() ;}
T2
这题的模型还是第一次见到,这题很明显是个DP。
关键在于这个DP的状态和转移,定义DP[i][j]为当前已经枚举到第i列,有j个右线段的左端点在i的左边,并且还未处理。注意,凡是我们i所到之处,右端点在i左边的左线段都必须被处理完。每次由i-1转移到i时,将右端点在该列的左线段全部处理了(相当于我们是需要把这些线段全部填充一个1,那么我们可以选择在之前的”空列&&当前列”选择一些列来使用,并且由于它们所在的行不一样,因此是排列而不是组合),并且判断左端点在i位置的右线段是否填充(如果我们把当前列用于右线段填充,那么对于左线段来说,他的可选空列就不包含当前列,但是同时由于左端点在当前位置的右线段可能有很多个,但是一列只能填充一个线段,因此还需要在排列数基础上*左端点在i位置的右线段数量),然后使用排列数和乘法原理转移。
#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;const int mmod = 998244353 ;int N , M , cL[3005] , cR[3005] , sL[3005] , sR[3005] , s[3005] ;int C[3001][3001] , fac[3001] = {1} , dp[3001][3001] ;int main(){// freopen( "matrix.in" , "r" , stdin ) ;// freopen( "matrix.out", "w" , stdout) ; scanf( "%d%d" , &N , &M ) ; for( int i = 0 ; i <= 3000 ; i ++ ){ C[i][0] = 1 ; for( int j = 1 ; j <= i ; j ++ ) C[i][j] = ( C[i-1][j] + C[i-1][j-1] ) %mmod ; } for( int i = 1 ; i <= 3000 ; i ++ ) fac[i] = 1LL * fac[i-1] * i %mmod ; for( int i = 1 , Li , Ri ; i <= N ; i ++ ){ scanf( "%d%d" , &Li , &Ri ) ; ++ cL[Li] ; ++ cR[Ri] ; } for( int i = 1 ; i <= M ; i ++ ){ sL[i] = sL[i-1] + cL[i] ; sR[i] = sR[i-1] + cR[i] ; s[i] = sL[i] + sR[i] ; } dp[0][0] = 1 ; for( int i = 1 ; i <= M ; i ++ ){ for( int j = 0 ; j <= sR[i-1] ; j ++ ){ if( !dp[i-1][j] ) continue ; int k = i - 1 - s[i-1] + j ; if( k < 0 ) continue ; dp[i][ j+cR[i] ] = ( dp[i][ j+cR[i] ] + 1LL * dp[i-1][j] * C[k+1][ cL[i] ] %mmod * fac[ cL[i] ] %mmod ) %mmod ; if( j + cR[i] ) dp[i][ j+cR[i]-1 ] = ( dp[i][ j+cR[i]-1 ] + 1LL * dp[i-1][j] * C[k][ cL[i] ] %mmod * fac[ cL[i] ] %mmod * ( cR[i] + j ) ) %mmod ; `` } printf( "%d" , dp[M][0] ) ;}
阅读全文
0 0
- NOIP模拟 2017.10.4 总结
- 2017.10.11 noip模拟赛 总结
- 2017.10.15 noip模拟赛 总结
- 9-4NOIP模拟赛总结
- 10-4NOIP模拟赛总结
- Noip模拟总结
- NOIP模拟8.12总结
- NOIP模拟20150904总结
- NOIP模拟9.19总结
- NOIP模拟10.27总结
- 10.28NOIP模拟总结
- NOIP模拟10.28总结
- NOIP模拟10.29总结
- 10.29NOIP模拟总结
- noip 11.5模拟总结
- 9.4NOIP模拟总结
- 9.21noip模拟总结
- 9.24NOIP模拟总结
- Linux 之GDB工具
- S3C6410启动方式及启动流程
- 织梦cms网上复制图片不可用的解决方法
- 关于photoshop使用的注意
- 剑指offer---最小的k个数
- NOIP模拟 2017.10.4 总结
- Java基础部分第十四节-正则
- SpringBoot四大神器之Actuator
- HTML 表格的制作
- 自我介绍??
- 第二章 SQL命令参考-ABORT
- numpy的应用案例
- Xcode 引 boost 库
- JAVA笔记概览