题目链接:http://www.kuangbinoj.com:8080/contest.php?cid=1007
在ACM交流群的第一场群赛,感觉题目还是不错的。
A : 给出一个 1元1次方程 , 求解
算是一个模拟题,我做法是将其化成 k1*x + c1 = k2 * x + c2 的形式
注意下 。 答案有可能是 -0 , 要弄回0 , 然后变量 x可能带数字 , k1-k2 可能是0 的情况
都考虑了的话肯定过了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <iostream> #include <queue> using namespace std ; const int N = 200010 ; typedef long long LL; typedef pair<int,int> pii ; #define X first #define Y second char s[N] , x[N] ; LL v , flag , sgin , nowk , k[2] , c[2] ; void Work() { if( flag ) { if( nowk == 0 ) nowk = 1 ; k[v] += sgin*nowk ; } else { c[v] += sgin*nowk ; } } bool check( int i ) { if( s[i] == '=' || s[i] == '+' || s[i] == '-' || ( s[i] >= '0' && s[i] <= '9' ) ) return true; return false ; } int Run() { int _ ; scanf("%d",&_); while( _-- ) { getchar(); scanf("%s",s); int len = strlen(s); v = 0 , flag = 0 ; sgin = 1 , nowk = 0 ; for( int i = 0 ; i < 2 ; ++i ) c[i] = k[i] = 0 ; for( int i = 0 ; i < len ; ++i ) { if( s[i] == '=' ) { Work(); sgin = 1 ; nowk = 0 ; flag = 0 ; v++; } else if( s[i] == '+' ) { Work(); sgin = 1 ; nowk = 0 ; flag = 0 ; } else if( s[i] == '-' ) { Work(); sgin = -1 ; nowk = 0 ; flag = 0 ; } else if( s[i] >= '0' && s[i] <= '9' ) { if( !flag ) nowk = nowk * 10 + ( s[i] - '0' ) ; } else { flag = 1 ; } } Work(); int tot = 0 , f = 0 ; for( int i = 0 ; i < len ; ++i ) { if( f && ( s[i] == '+' || s[i] == '-' || s[i] == '=' ) ) { break ; } else if( !f && check(i) ) { continue ; } else { x[tot++] = s[i] ; x[tot] = 0 ; f = 1 ; } } double ans ; int cc = ( c[1] - c[0] ) , kk = ( k[0] - k[1] ) ; if( kk == 0 ) ans = 0 ; else ans = 1.0 * cc / kk ; if( ans == 0 ) ans = 0 ; printf("%s=%.3lf ",x,ans); } return 0 ; } int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif // LOCAL ios::sync_with_stdio(0); return Run() ; } /************************************************************** Problem: 1220 User: hl_mark Language: C++ Result: 正确 Time:0 ms Memory:1928 kb ****************************************************************/
B. 给出一个长是S的数字串, 问划分成 n + 1 分 相乘得到的数字最大是多少 。
S长度是 40 。 然后就写了一个大数+dp 。
dp[i][j] 表示分成了 i 分 , 分到第j 个数字得到最大结果是什么 。
转移就是
dp[i][j] = max { dp[i][j] , dp[i-1][k] * num( k +1 , j ) [ i - 1 <= k < j ] } ..
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <iostream> #include <queue> using namespace std ; const int N = 200010 ; typedef long long LL; #define MAXN 9999 #define mod 10000 #define MAXSIZE 1010 #define DLEN 4 class BigNum { private: int a[400]; int len ; public: BigNum(){ len = 1 ; memset( a , 0 , sizeof a ) ; } BigNum(const char *); BigNum &operator=(const BigNum &); BigNum operator*(const BigNum &)const; bool operator > ( const BigNum &T )const ; void print(); }; BigNum::BigNum( const char *s ) { int t , k , index , L , i ; memset( a , 0 , sizeof a ) ; L = strlen(s); len = L/DLEN; if( L % DLEN ) len++ ; index = 0 ; for( int i = L - 1 ; i >= 0 ; i -= DLEN ) { t = 0 ; k = i - DLEN + 1 ; if( k < 0 ) k = 0; for( int j = k ; j <= i ; j++ ) { t = t*10+s[j]-'0'; } a[index++] = t ; } } BigNum BigNum::operator * ( const BigNum &T )const { BigNum res ; for( int i = 0 ; i < len ; ++i ) { int up = 0 ; for( int j = 0 ; j < T.len ; ++j ) { int tmp = a[i] * T.a[j] + res.a[i+j] + up; res.a[i+j] = tmp % mod ; up = tmp / mod ; } if( up != 0 ) res.a[i+T.len] = up ; } res.len = len + T.len ; while( res.a[res.len-1] == 0 && res.len > 1 ) res.len-- ; return res ; } bool BigNum::operator > ( const BigNum &T )const { int ln ; if( len > T.len ) { return true ; } else if( len == T.len ) { ln = len - 1 ; while( a[ln] == T.a[ln] && ln > 0 ) ln-- ; if( ln >= 0 && a[ln] > T.a[ln] ) return true ; else return false ; } else { return false; } } BigNum &BigNum::operator=( const BigNum &T ){ int i ; len = T.len ; memset( a, 0 , sizeof a ) ; for( int i = 0 ; i < len ; ++i ) a[i] = T.a[i] ; return *this ; } void BigNum::print() { int i ; printf("%d",a[len-1]); for( i = len - 2 ; i >=0 ; --i ) printf("%04d",a[i]); printf(" "); } BigNum dp[8][44] ; int n , m ; char ss[44] , s[44]; void toString( int i , int j ) { int tot = 0 ; for( int y = i ; y <= j ; ++y ) ss[tot++] = s[y] ; ss[tot] = 0 ; } void init() { for( int i = 0 ; i <= m ; ++i ) { for( int j = 0 ; j <= n ; ++j ) dp[i][j] = "0"; } int tot = 0 ; for( int i = 0 ; i < n ; ++i ) { ss[tot++] = s[i] ; dp[0][i] = ss ; } } int Run() { while( ~scanf("%d%d",&n,&m)) { scanf("%s",s); init(); for( int i = 1 ; i <= m ; ++i ) { for( int j = i ; j < n ; ++j ) { for( int k = i - 1 ; k < j ; ++k ) { toString( k + 1 , j ) ; BigNum w = BigNum(ss) ; BigNum tmp = dp[i-1][k] * w ; if( tmp > dp[i][j] ) { dp[i][j] = tmp ; } } } } dp[m][n-1].print(); } return 0 ; } int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif // LOCAL ios::sync_with_stdio(0); return Run() ; } /************************************************************** Problem: 1221 User: hl_mark Language: C++ Result: 正确 Time:0 ms Memory:2088 kb ****************************************************************/
C. 将20个单词进行接龙 , 问能得到最长的单词的长度
就设一个 dp[st][i] , 表示用了st状态中的单词,最后一个单词是 i 能得到的最长长度 。
两个单词能够接龙的条件是, 前一个单词的后缀跟后一个单词的后缀相同 。
有给出第一个单词的首字母..所以我就直接 spfa ..
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <iostream> #include <queue> using namespace std ; const int N = 1<<20 ; typedef pair<int,int> pii ; #define X first #define Y second int dp[N][22], n ; string s[22] ; char start ; int ans = 0 ; int cal( int x , int y ) { int res = -1 ; for( int i = s[x].length() - 1 ; i >= 0 ; --i ) { bool tag = false ; if( s[x].length() - i > s[y].length() ) continue ; for( int j = 0 ; j + i < s[x].length() ; ++j ) { if( s[x][i+j] != s[y][j] ) break ; if( j + i == s[x].length() - 1 ) tag = true ; } if( tag ) res = max( res , (int)s[y].length() - (int)s[x].length() + i ) ; } return res ; } bool inq[N][22] ; void bfs() { queue<pii>que; memset( inq , false , sizeof inq ) ; memset( dp , 0 , sizeof dp ) ; for( int i = 0 ; i < n ; ++i ) { if( s[i][0] == start ) { que.push( pii(1<<i,i) ) ; dp[1<<i][i] = s[i].length(); inq[1<<i][i] = true ; } } while( !que.empty() ) { int st = que.front().X , ed = que.front().Y ; que.pop(); ans = max( ans , dp[st][ed] ); inq[st][ed] = false ; for( int i = 0 ; i < n ; ++i ) { if( st&(1<<i) ) continue ; int w = cal( ed , i ) ; if( w == -1 ) continue ; int vst = st|(1<<i) ; if( dp[vst][i] < dp[st][ed] + w ) { dp[vst][i] = dp[st][ed] + w ; if( !inq[vst][i] ) { inq[vst][i] = true ; que.push( pii(vst,i) ); } } } } } int Run() { while( cin >> n ) { for( int i = 0 ; i < n ; ++i ) cin >> s[i] ; cin >> start ; ans = 0 ; bfs(); cout << ans << endl ; } return 0 ; } int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif // LOCAL ios::sync_with_stdio(0); return Run() ; }
D. 一个很水的整数划分
将整数T分成N份,每份里面必须有数不能空,且不能有相同的分法(不考虑顺序)
dp[i][j]表示 i 分成了 j 分的个数 。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <iostream> using namespace std ; const int N = 22 ; int dp[205][10] , n , k ; int Run() { while( cin >> n >> k ) { memset( dp , 0 ,sizeof dp ); dp[0][0] = 1 ; for( int i = 1 ; i <= n ; ++i ) { for( int j = i ; j <= n ; ++j ) { for( int z = 1 ; z <= k ; ++z ) { dp[j][z] += dp[j-i][z-1] ; } } } cout << dp[n][k] << endl ; } return 0 ; } int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif // LOCAL ios::sync_with_stdio(0); return Run() ; }
E . 最短路变形 。
http://www.cnblogs.com/hlmark/p/4395271.html
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <queue> #include <iostream> #include <map> #include <stack> using namespace std ; typedef pair<int,int> pii ; #define X first #define Y second const int N = 1010 ; const int inf = 1e9+7 ; typedef long long LL; int n , xx[N] , pre[N] , ww[N] , tot ; vector<pii>g[N]; struct node { int a , c , d , id ; node(){}; node( int a , int c , int d , int id ):a(a),c(c),d(d),id(id){} bool operator < ( const node &A ) const { if( d != A.d ) return d > A.d ; else if( c != A.c ) return c > A.c ; else { stack<int>s1 , s2; int id1 = id , id2 = A.id ; while( id1 != -1 ) { s1.push( xx[id1] ); id1 = pre[id1] ; } while( id2 != -1 ) { s2.push( xx[id2] ); id2 = pre[id2] ; } while( !s1.empty() ) { int a = s1.top() ; s1.pop() ; int b = s2.top() ; s2.pop() ; if( a > b ) return true ; } return false ; } } }; int bestpath[N] , bestcnt , bestcost ; int tmppath[N] , tmpcnt , tmpcost ; void Choose_best( int id , int cnt ) { if( tmpcost > bestcost ) return ; stack<int>s ; while( id != -1 ) { s.push( xx[id] ); id = pre[id] ; } tmpcnt = 0 ; while( !s.empty() ) { tmppath[tmpcnt++] = s.top() ; s.pop() ; } if( tmpcost < bestcost ) { bestcnt = tmpcnt ; bestcost = tmpcost ; for( int i = 0 ; i < tmpcnt ; ++i ) bestpath[i] = tmppath[i] ; return ; } if( cnt > bestcnt ) return ; else if( cnt < bestcnt ) { bestcnt = tmpcnt ; for( int i = 0 ; i < tmpcnt ; ++i ) bestpath[i] = tmppath[i] ; } else { for( int i = 0 ; i < tmpcnt ; ++i ) { if( bestpath[i] > tmppath[i] ) { for( int j = i ; j < bestcnt ; ++j ) { bestpath[j] = tmppath[j] ; } } else if ( bestpath[i] < tmppath[i] ) { break ; } } } } int dis[N] ; void dij() { memset( dis , 0x3f , sizeof dis ); priority_queue<node>que; tot = 0 ; xx[tot] = 0 , pre[tot] = -1 ; tot++ ; que.push( node(0,0,0,tot-1) ); dis[0] = 0 ; while( !que.empty() ) { int u = que.top().a , cnt = que.top().c , cost = que.top().d , id = que.top().id ; que.pop(); if( cost > dis[u] ) continue ; if( u == 1 ) { if( dis[u] ) { tmpcost = dis[u] ; Choose_best( id , cnt ); } return ; } for( int i = 0 ; i < g[u].size() ; ++i ) { int v = g[u][i].X , w = ww[g[u][i].Y] ; if( dis[v] > dis[u] + w ) { dis[v] = dis[u] + w ; xx[tot] = v ; pre[tot] = id ; tot++; que.push( node( v , cnt+1 , dis[v] , tot - 1 ) ) ; } } } } void Gao() { dij(); for( int i = 0 ; i < n ; ++i ) { int cc = ww[i] ; ww[i] = 0 ; dij(); for( int j = i + 1 ; j < n ; ++j ) { int dd = ww[j] ; ww[j] = 0 ; dij(); ww[j] = dd ; } ww[i] = cc ; } for( int i = 0 ; i < bestcnt ; ++i ) cout << bestpath[i] << ' ' ; cout << bestcost << endl ; } int Run() { while( cin >> n && n ) { bestcost = bestcnt = inf ; for( int i = 0 ; i < N ; ++i ) g[i].clear(); for( int i = 0 ; i < n ; ++i ) { int u , v , w ; cin >> u >> v >> w ; ww[i] = w ; g[u].push_back(pii(v,i)); g[v].push_back(pii(u,i)); } Gao(); } return 0 ; } int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif // LOCAL ios::sync_with_stdio(0); return Run(); }
F. 给出两个字符串,问两个串的循环节中有多少个是一样的。
貌似有其他KMP什么的解法。
我做法是先 O( sqrt n ) 把串长的约数分解出来 。
然后暴力一下那些约数的循环节是否可行的 。 最坏情况就是所有都不可行 。 O( n * sqrt(n) ) , n 是 1e5 不卡根号
然后最后判下两个串可行的循环节是否相同就OK了 ~
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <iostream> #include <queue> #include <algorithm> using namespace std ; const int N = 200010 ; typedef long long LL; typedef pair<int,int> pii ; char s[2][N] ; int n , fac[N] , tot ; void Gao() { tot = 0 ; for( int i = 1 ; i * i <= n ; ++i ) { if( n % i == 0 ) { fac[tot++] = i ; if( n / i != i ) fac[tot++] = n / i ; } } sort( fac , fac + tot ) ; } bool check( int x , char *str ) { for( int i = x ; i < n ; ++i ) { if( str[i] != str[i%x] ) { return false ; } } return true ; } bool check2( int x ) { for( int i = 0 ; i < x ; ++i ) { if( s[0][i] != s[1][i] ) return false ; } return true ; } bool vis[N] , can[N][2]; void Work( int v ) { memset( vis , false , sizeof vis ); for( int i = 0 ; i < tot ; ++i ) if( !vis[i] ) { // O( sqrt(n) ); if( check( fac[i] , s[v] ) ) { // O( n ) can[ fac[i] ][v] = true ; for( int j = i + 1 ; j < tot ; ++j ) if( fac[j] % fac[i] == 0 ) { can[ fac[j] ][v] = vis[j] = true ; } } } } int Run() { while( ~scanf("%s%s",s[0],s[1])) { memset( can , false , sizeof can ); n = strlen(s[0]); Gao(); Work(0); n = strlen(s[1]); Gao(); Work(1); int ans = 0 ; for( int i = 0 ; i < tot ; ++i ) if( can[ fac[i] ][0] && can[ fac[i] ][1] && check2( fac[i] ) ) { ans++ ; } printf("%d ",ans); } return 0 ; } int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif // LOCAL ios::sync_with_stdio(0); return Run() ; }
G。搜索题。。没写到~