A。题目:http://acm.timus.ru/problem.aspx?space=1&num=2024
题意:求一个包含K个不同字符的集合的最大长度,还有组成这个长度的集合的个数
做法:因为求的集合,不需连续 ,直接统计各个字符的出现次数 。
那么答案一就是按出现次数排序再加前K个。
答案二只与K个中集合大小最小的分配相关。
/* hl */ #include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pii; char s[100010]; ll c[30][30]; ll calc(int n, int m) { ll res = 1; for(int i=1; i<=m; i++) { res *= n-i+1; res /= i; } return res; } void c_init() { for(int i=1; i<=26; i++) for(int j=0; j<=26; j++) c[i][j] = calc(i, j); } struct node { ll cnt ; int vis ; bool operator <( const node &a ) const{ if( vis!=a.vis ) return vis >a.vis ; else return cnt > a.cnt ; } }e[30]; void init() { for( int i = 0 ; i < 26 ; ++i ) e[i].cnt = e[i].vis = 0 ; } int main() { #ifdef LOCAL freopen("in","r",stdin); #endif c_init(); int k ; while( ~scanf("%s%d",s,&k) ) { int len = strlen(s); init(); for( int i = 0 ; i < len ; ++i ) { e[ s[i] - ‘a‘ ].cnt ++ ; e[ s[i] - ‘a‘ ].vis = 1 ; } sort( e , e + 26 ) ; ll ans1 = 0 , ans2 = 1 , last = -1 ; int tmp = 0 ; for( int i = 0 ; i < k && e[i].vis ; ++i ) { ans1 += e[i].cnt; if( e[i].cnt == last ) tmp++ ; else { last = e[i].cnt ; tmp = 1 ; } } int all = 0 ; for( int i = 0 ; i < 26 && e[i].vis ; ++i ) { if( e[i].cnt == last ) all++ ; } ans2 = c[all][tmp]; printf("%I64d %I64d\n",ans1,ans2); } return 0; }
B. 题目 : http://acm.timus.ru/problem.aspx?space=1&num=2025
题意 : n 个人分到 k 个组 ,不同组的人可以打架 , 求打架次数最多是多少
平均分配后 , 处理一个前缀/后缀和,然后一个个组统计
/* hl */ #include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pii; const int N = 10010; int x[N] , sum[N] ; int main() { #ifdef LOCAL freopen("in","r",stdin); #endif int _ , n , m ; scanf("%d", &_); while(_--) { scanf("%d%d",&n,&m); for( int i = 1 ; i <= m ; ++i ) { x[i] = n / m ; } int c = n % m ; for( int i = 1 ; i <= m && i <= c ; ++i ) { x[i]++ ; } sum[m] = x[m] ; for( int i = m - 1 ; i >= 1 ; --i ) sum[i] = sum[i+1] + x[i] ; int ans = 0 ; for( int i = 1 ; i < m ; ++i ) { ans += x[i] * sum[i+1] ; } printf("%d\n",ans); } return 0; }
C. 题目: http://acm.timus.ru/problem.aspx?space=1&num=2026
题意 : n 节课 .. 不同字母不同课 , ‘?’代表未确定 ,
奇位置加字符权,偶位置减字符权 , 问至少安排k节不同的课能够得到的最大权
若然,已经够k个不同字符就直接贪心放
不然,先统计奇偶位置的问号 , 再看看应该在奇问号,还是在偶问号处放新字符。
这就要选跟最优字符的距离较小的那个新字符了
放够了剩下的就贪心
/* hl */ #include <bits/stdc++.h> using namespace std ; string s ; int k ; bool vis[30] ; queue<int> o , e ; int Run() { while( cin >> s >> k ) { memset( vis , false , sizeof vis ) ; int c = 0 , cnt1 = 0 , cnt2 = 0 ; for( int i = 0 ; i < s.length() ; ++i ) { if( s[i] == ‘?‘) { if( i&1 ) cnt2++ ; else cnt1++ ; } else if( !vis [ s[i] - ‘a‘ ] ) { vis[ s[i] - ‘a‘ ] = true , c++ ; } } //cout << cnt1 << ‘ ‘ << cnt2<< ‘ ‘ << c << endl ; if( cnt1 + cnt2 + c < k ) { cout << "-1" << endl ; continue ; } for( int i = c ; i < k ; ++i ) { int c1 = -1 , c2 = 26 ; for( int j = 25 ; j >= 0 ; --j ) if( !vis[j] ) { c1 = j ; break ; } for( int j = 0 ; j < 26 ; ++j ) if( !vis[j] ) { c2 = j ; break ; } if( 25 - c1 <= c2 && cnt1 ) { cnt1-- ; vis[c1] = true ; o.push(c1); } else { vis[c2] = true ; e.push(c2); } } for( int i = 0 ; i < s.length() ; ++i ) { if( s[i] == ‘?‘ ) { if( i&1 ) { // even position if( !e.empty() ) { s[i] = e.front() + ‘a‘ ; e.pop() ; } else s[i] = ‘a‘ ; } else { if( !o.empty() ) { s[i] = o.front() + ‘a‘ ; o.pop() ; } else s[i] = ‘z‘ ; } } } cout << s << endl ; } return 0 ; } int main() { // freopen("in.txt","r",stdin); ios::sync_with_stdio(0) ; return Run(); }
D :http://acm.timus.ru/problem.aspx?space=1&num=2027
模拟题
blue :
用一个数组保存整个程序
用一个pii的指针保存指针的位置
用一个27位的数组保存寄存器
剩下就是模拟了,注意异常的处理
其实我写的复杂,写烂了。。后来想想应该是十几分钟写完的代码
/* blue */ #include <bits/stdc++.h> using namespace std; #define rep(i, l, r) for(i=(l); i<(r); i++) #define drep(i, l, r) for(int i=(l); i<(r); i++) typedef long long ll; typedef pair<int,int> pii; const int N = 105; // Exception define #define OE 0 #define RE 1 #define TLE 2 #define OK 3 char EXCEPTION[][30] = {"OVERFLOW ERROR","RUNTIME ERROR","TIME LIMIT EXCEEDED"}; // global int n,m; char program[N][N]; // input stream system int read_pos, read_cnt, read_num[100010]; void read_init() { read_pos = 0; scanf("%d", &read_cnt); for(int i=0; i<read_cnt; i++) scanf("%d", read_num+i); } int read_next() { if(read_pos >= read_cnt) return read_num[read_cnt-1]; return read_num[read_pos++]; } // pointer system pii pointer; #define xx first #define yy second int dir; const int dx[] = {0,1,0,-1}; const int dy[] = {1,0,-1,0}; inline bool inside(const int &x, const int &y) {return x>=0&&x<n && y>=0&&y<m;} int move() { pointer.xx += dx[dir]; pointer.yy += dy[dir]; if(!inside(pointer.xx, pointer.yy)) return RE; return OK; } void changedir(char c) { if(c==‘>‘) dir = 0; else if(c==‘v‘) dir = 1; else if(c==‘<‘) dir = 2; else dir = 3; } // REG system int reg[30]; #define CURREG reg[26] void swap_reg(char c) { int t = reg[c-‘A‘]; reg[c-‘A‘] = CURREG; CURREG = t; } // INC and DEC int INC() { CURREG++; if(CURREG > 100000 || CURREG < -100000) return OE; return OK; } int DEC() { CURREG--; if(CURREG > 100000 || CURREG < -100000) return OE; return OK; } // At @ void At() { if(CURREG==0) dir--; else dir++; if(dir<0) dir=3; if(dir>3) dir=0; } // choose command system #define CMD program[pointer.xx][pointer.yy] inline bool isDir() {return CMD==‘v‘ || CMD==‘^‘ || CMD==‘<‘ || CMD==‘>‘;} inline bool isREG() {return CMD>=‘A‘ && CMD<=‘Z‘;} inline bool isRead() {return CMD==‘?‘;} inline bool isWrite() {return CMD==‘!‘;} inline bool isINC() {return CMD==‘+‘;} inline bool isDEC() {return CMD==‘-‘;} inline bool isAt() {return CMD==‘@‘;} inline bool isTerminal() {return CMD==‘#‘;} int main() { #ifdef LOCAL freopen("in","r",stdin); #endif while(scanf("%d%d", &n, &m)!=EOF) { memset(reg, 0, sizeof(reg)); // read program for(int i=0; i<n; i++) scanf("%s", program[i]); // input stream read_init(); // pointer pointer = pii(0, 0); dir = 0; int cnt = 0; while(true) { cnt++; if(cnt>1000000) { puts(EXCEPTION[TLE]); break; } int status = OK; if(isDir()) changedir(CMD); else if(isREG()) swap_reg(CMD); else if(isRead()) CURREG = read_next(); else if(isWrite()) {printf("%d\n", CURREG);CURREG=0;} else if(isINC()) status = INC(); else if(isDEC()) status = DEC(); else if(isAt()) At(); else if(isTerminal()) break; if(status != OK) { puts(EXCEPTION[status]); break; } if(status != OK) { puts(EXCEPTION[status]); break; } status = move(); if(status != OK) { puts(EXCEPTION[status]); break; } } } return 0; }
赛后我自己也写了一次。
注意下 TLE 的判断 要符合这句话 :
If the termination operator is not executed during 106 steps and none of the above two errors occurs, then the program terminates with TIME LIMIT EXCEEDED.
然后还要注意得先判 OVE 再判 RE. ,这里我wa了好几发才发现
/* hl */ #include <bits/stdc++.h> using namespace std ; const int N = 101 ; const int TLE = 1000000; #define OVE 100000 int h , w ; string mp[N] ; int dx[] = { 0 , 1 , 0 , -1 } ; int dy[] = { 1 , 0 , -1 , 0 } ; int x , y , dir , tim ; int scan[100010] , reg[30] ; int Run() { while( cin >> h >> w ) { for( int i = 0 ; i < h ; ++i ) cin >> mp[i] ; int n ; cin >> n ; for( int i = 0 ; i < n ; ++i ) cin >> scan[i] ; dir = x = y = tim = 0 ; int c = 0 , cur = 0 ; bool finish = false ; memset( reg , 0 , sizeof reg ) ; while( true ) { tim++ ; switch( mp[x][y] ) { case ‘>‘ : dir = 0 ; break ; case ‘v‘ : dir = 1 ; break ; case ‘<‘ : dir = 2 ; break ; case ‘^‘ : dir = 3 ; break ; case ‘.‘ : break; case ‘?‘ : cur = scan[c>=n?n-1:c] ; c++; break ; case ‘!‘ : cout<<cur<<endl ; cur = 0 ; break ; case ‘+‘ : cur++ ; break ; case ‘-‘ : cur-- ; break ; case ‘@‘ : dir = ( cur ? ( dir + 1 ) % 4 : ( dir + 3 ) % 4 ) ; break ; case ‘#‘ : finish = true ; break ; default : swap( cur , reg[ mp[x][y] - ‘A‘ ] ) ; break; } if( finish ) break ; x += dx[dir] ; y += dy[dir] ; if( cur > OVE || cur < -OVE ) { cout << "OVERFLOW ERROR" << endl; break ; } else if( x < 0 || x >= h || y < 0 || y >= w ) { cout << "RUNTIME ERROR" << endl; break ; } else if( tim == TLE ) { cout << "TIME LIMIT EXCEEDED" << endl; break ; } } } return 0 ; } int main() { // freopen("in.txt","r",stdin); ios::sync_with_stdio(0) ; return Run(); }
E:http://acm.timus.ru/problem.aspx?space=1&num=2028
题目要求给一个数1 n .. 先弄一个输入,然后再输入 1 n ,放到D题能够跑出前 n 项和 。
做法: 根据D题,数字每次操作只能够+1 ,还有交换操作当前寄存器和内存寄存器的值 , 一个判断操作@ ,能够判当前寄存器是否为 0 。
当前寄存器用reg表示, 其余寄存器 A~Z吧
如何把一个数n弄成两个呢? 直接把这个数放到reg上,每次-1,就换出A来+1 , 换出B+1 。
用@判出reg值为0 的时候, A , B 就有n了
然后再用一个C来保存结果 。 A 复制成两个后 , 把B也像上述操作一样加到C上 , 直到B为0 。
A不等于0 ? A的值 -1 , 复制到B上 ,进行操作1 。
A 等于0 ? 输出C 。
然后画一下图, 按照D题题意换成字符就OK了 。
/* hl */ #include <bits/stdc++.h> using namespace std ; int h , w ; string s[] = { "?......A.>..v..........<", "...............>C.!#....", "[email protected]>[email protected]", "...............>.>....v.", "..............>..^......", "[email protected]+BA+A<.", "..............>..A-AB..^", ".>C+C-...^.............." }; int Run() { cout << 8 << ‘ ‘ << 24 << endl ; for( int i = 0 ; i < 8 ; ++i ) cout << s[i] << endl ; return 0 ; } int main() { // freopen("in.txt","r",stdin); ios::sync_with_stdio(0) ; return Run(); }
F: http://acm.timus.ru/problem.aspx?space=1&num=2029
汉诺塔变形吧。 题意就是把一个全部放在A汉诺塔 移成 给出的状态
可以发现所有状态都是可以得到的,只要你合法地移动
要明白 , 移动第i个到目标位置 。
如果第i个已经在目标位置的话,可以直接忽略它了。然后去处理第 i - 1 个 。
如果不在目标位置,要把第 i 个移动到目标位置 ,必须把上面的 i -1 个移动到 除 原位置 和 目标位置 的那个位置上 , 需要 2^( i-1)-1 步 。
加上自己移动的那一步就是 2^( i-1) 因为移动的位置唯一,这里是无可避免的 , 必须加到答案上 。
/* hl */ #include <bits/stdc++.h> using namespace std ; typedef long long LL; int n ; string s ; LL ans ; void dfs( int dep , int pos ) { if( dep < 0 ) return ; int goal = s[dep] - ‘A‘ ; // cout << dep << ‘ ‘ << pos << ‘ ‘ << ans << endl ; if( goal == pos ) dfs( dep - 1 , pos ) ; else { ans += (1LL<<dep) ; if( pos == 0 ) { if( goal == 2 ) dfs( dep - 1 , 1 ) ; else dfs( dep - 1 , 2 ) ; } else if( pos == 1 ) { if( goal == 0 ) dfs( dep - 1 , 2 ) ; else dfs( dep - 1 , 0 ) ; } else { if( goal == 1 ) dfs( dep - 1 , 0 ) ; else dfs( dep - 1 , 1 ) ; } } } int Run() { while( cin >> n >> s ) { ans = 0 ; dfs( s.length() - 1 , 0 ) ; cout << ans << endl ; } return 0 ; } int main() { // freopen("in.txt","r",stdin); ios::sync_with_stdio(0) ; return Run(); }
G: http://acm.timus.ru/problem.aspx?space=1&num=2030
有3种做法:
O( n + m ) : 转成有根树 , 在线更新父亲,离线更新儿子 。
更新的时候就是 父亲的离线值 + 自身的在线值 。
然后按照上面讲的来更新
/* VM */ #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <iostream> #include <vector> using namespace std; #define rep(i, n) for(int i = 0; i < (n); ++i) #define rep1(i, n) for(int i = 1; i <= (n); ++i) #define For(i, b, e, s) for(int i = (b); i != (e); i += (s)) const int N = 100005; const int mod = 1000000007; vector<int> G[N]; int par[N], val[N], add[N], n; void dfs(int u, int p){ par[u] = p; for(unsigned int i = 0; i < G[u].size(); ++i) if(G[u][i] != p) dfs(G[u][i], u); } int main(){ int u, v, m; while(scanf("%d", &n) == 1){ rep(i, n + 1) G[i].clear(); memset(add, 0, sizeof(add[0]) * (n + 1)); rep1(i, n) scanf("%d", &val[i]); rep(i, n - 1){ scanf("%d%d", &u, &v); G[u].push_back(v); G[v].push_back(u); } dfs(1, 0); scanf("%d", &m); while(m--){ scanf("%d%d", &u, &v); if(u == 1){ int t = val[v] + add[par[v]]; if(t >= mod) t-= mod; if((val[par[v]] += t) >= mod) val[par[v]] -= mod; if((add[v] += t) >= mod) add[v] -= mod; } else{ int t = val[v] + add[par[v]]; if(t >= mod) t-= mod; printf("%d\n", t); } } } return 0; }
O( n logn )
转成有根树 ,再bfs一次把树给分成一层层 , 同一个父亲的结点编号要连续 。
然后就是用一个能够区间 logn 操作的数据结构进行 单点查询,对父亲单点更新, 对孩子成段更新 。
/* hl */ #include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pii; #define X first #define Y second const int N = 100100; const int mod = 1e9+7; int n , fa[N] , cnt , idx[N] , l_s[N] , r_s[N] , x[N] ; vector<int>g[N]; void bfs() { int cnt = 1 ; memset( l_s , 0x3f , sizeof l_s ); memset( r_s , -1 , sizeof r_s ); queue<pii>que; que.push( pii(1,0) ) ; while( !que.empty() ) { int u = que.front().X , pre = que.front().Y ; que.pop(); fa[u] = pre ; idx[u] = cnt++ ; l_s[pre] = min( l_s[pre] , idx[u] ); r_s[pre] = max( r_s[pre] , idx[u] ); for( int i = 0 ; i < g[u].size() ; ++i ) { int v = g[u][i] ; if( pre == v ) continue ; que.push( pii( v,u ) ) ; } } } ll c[N]; void init() { memset( c , 0 , sizeof c ); } int lowbit( int x ) { return x&-x; } void update( int pos , ll key ) { while( pos < n + 10 ) { c[pos] = ( c[pos] + key + mod ) % mod ; pos += lowbit(pos); } } ll query( int pos ) { ll res = 0 ; if( !pos ) return 0 ; while( pos > 0 ) { res = ( res + c[pos] ) % mod ; pos -= lowbit(pos); } return res ; } int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif while( ~scanf("%d",&n) ) { for( int i = 1 ; i <= n ; ++i ) scanf("%d",&x[i]); for( int i = 1 ; i <= n ; ++i ) g[i].clear(); for( int i = 1 ; i < n ; ++i ) { int u , v ; scanf("%d%d",&u,&v); g[u].push_back(v); g[v].push_back(u); } bfs(); init(); for( int i = 1 ; i <= n ; ++i ) { update( idx[i] , x[i] ); update( idx[i] + 1 , -x[i] ); } int m ; scanf("%d",&m); while( m -- ) { int op , c ; scanf("%d%d",&op,&c); if( op == 1 ) { ll v = query( idx[c] ) ; if( c != 1 ) { update( idx[ fa[c] ] , v ) ; update( idx[ fa[c] ] + 1 , -v ) ; } if( r_s[c] != -1 ) { update( l_s[c] , v ) ; update( r_s[c] + 1 , -v ) ; } } else { printf("%I64d\n",query( idx[c] )); } } } return 0; }
树分层+树状数组
用树状数组要注意一点就是 差分的时候有减操作 , 取模后有负数出现 , (x % mod + mod ) % mod 就可以解决了 。
线段树的话可以避免上面的差错 , 不过不知道训练中何解WA , 重新写过一次然后就过了
/* hl */ #include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pii; #define X first #define Y second const int N = 100100; const int mod = 1e9+7; #define root 1,n+20,1 #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define lr rt<<1 #define rr rt<<1|1 int n , fa[N] , cnt , idx[N] , l_s[N] , r_s[N] ; ll x[N] ; vector<int>g[N]; ll date[N<<2] , lazy[N<<2] ; void build( int l , int r , int rt ){ date[rt] = lazy[rt] = 0 ; if( l == r ) return ; int mid = (l+r)>>1; build(lson) , build(rson) ; } void Down( int rt ) { if( lazy[rt] ) { date[lr] = ( date[lr] + lazy[rt] ) % mod ; date[rr] = ( date[rr] + lazy[rt] ) % mod ; lazy[lr] = ( lazy[lr] + lazy[rt] ) % mod ; lazy[rr] = ( lazy[rr] + lazy[rt] ) % mod ; lazy[rt] = 0 ; } } void update( int l , int r , int rt , int L , int R , ll v ) { if( l == L && r == R ) { date[rt] = ( date[rt] + v ) % mod ; lazy[rt] = ( lazy[rt] + v ) % mod ; return ; } Down( rt ) ; int mid = (l+r)>>1; if( R <= mid ) update( lson , L , R , v ) ; else if( L > mid ) update( rson , L , R , v ) ; else update( lson , L , mid , v ) , update( rson , mid + 1 , R , v ) ; } ll query( int l , int r , int rt , int x ) { if( l == r ) { return date[rt] ; } Down( rt ) ; int mid = (l+r)>>1; if( x <= mid ) return query( lson , x ) ; else return query( rson , x ); } void bfs() { int cnt = 1 ; memset( l_s , 0x3f , sizeof l_s ); memset( r_s , -1 , sizeof r_s ); queue<pii>que; que.push( pii(1,0) ) ; while( !que.empty() ) { int u = que.front().X , pre = que.front().Y ; que.pop(); fa[u] = pre ; idx[u] = cnt++ ; l_s[pre] = min( l_s[pre] , idx[u] ); r_s[pre] = max( r_s[pre] , idx[u] ); for( int i = 0 ; i < g[u].size() ; ++i ) { int v = g[u][i] ; if( pre == v ) continue ; que.push( pii( v,u ) ) ; } } } int main() { ios::sync_with_stdio(0) ; while( cin >> n ) { for( int i = 1 ; i <= n ; ++i ) cin >> x[i] ; for( int i = 1 ; i <= n ; ++i ) g[i].clear(); for( int i = 1 ; i < n ; ++i ) { int u , v ; cin >> u >> v ; g[u].push_back(v); g[v].push_back(u); } bfs(); build(root); for( int i = 1 ; i <= n ; ++i ) update( root , idx[i] , idx[i] , x[i] ); int m ; cin >> m ; while( m -- ) { int op , c ; cin >> op >> c ; if( op == 1 ) { ll v = query( root , idx[c] ) ; if( c != 1 ) { update( root , idx[ fa[c] ] , idx[ fa[c] ] , v ) ; } if( r_s[c] != -1 ) { update( root , l_s[c] , r_s[c] , v ) ; } } else { cout << query( root , idx[c] ) << endl ;; } } } return 0; }
线段树
O( n sqrt(n) )
把结点分层两类, 孩子结点大于 sqrt(n) 个的 , 孩子结点小于 sqrt(n) 。
对前面的离线更新, 后面的在线更新 。
/* lys */ #include <bits/stdc++.h> using namespace std; const int UB = 111; const int N = 111111; const int MOD = 1e9 + 7; vector<int> nx[N], bnx[N]; int sum[N], out[N]; void Add(int &a, const int b) { a += b; if (a >= MOD) { a -= MOD; } } int Run() { int n; while (cin >> n) { int x, y; for (int i = 1; i <= n; ++i) { nx[i].clear(); cin >> sum[i]; out[i] = 0; } for (int i = 1; i < n; ++i) { cin >> x >> y; nx[x].push_back(y); nx[y].push_back(x); } for (int i = 1; i <= n; ++i) { for (int j = 0; j < nx[i].size(); ++j) { if (nx[nx[i][j]].size() > UB) { bnx[i].push_back(nx[i][j]); } } } int m; cin >> m; for (int i = 0; i < m; ++i) { cin >> x >> y; if (x == 1) { if (nx[y].size() > UB) { for (int i = 0; i < bnx[y].size(); ++i) { Add(sum[bnx[y][i]], sum[y]); } Add(out[y], sum[y]); } else { int s = sum[y]; for (int i = 0; i < nx[y].size(); ++i) { Add(s, out[nx[y][i]]); } for (int i = 0; i < bnx[y].size(); ++i) { Add(sum[bnx[y][i]], s); } Add(out[y], s); } } else { if (nx[y].size() > UB) { cout << sum[y] << endl; } else { int s = sum[y]; for (int i = 0; i < nx[y].size(); ++i) { Add(s, out[nx[y][i]]); } cout << s << endl; } } } } return 0; } int main() { ios::sync_with_stdio(0); return Run(); }
H: http://acm.timus.ru/problem.aspx?space=1&num=2031
全过了,忽略
I :http://acm.timus.ru/problem.aspx?space=1&num=2032
blue :
原理就是固定三角形一个点在原点上,那剩下就是找两个点,然后判断一下长度是否符合题目给出的三条边长
根据题目给出的边长A,可以在o(len)找出这些符合条件的点。
就是枚举x坐标,然后看y坐标是否符合,不符合就y--,x越大的话y肯定要越小。同理用同样的方法找出边长B对应的整点。这样找出来满足条件的整点其实数量是很少的。
然后就是枚举这两组顶点的组合,看看这两个点连起来的长度是否为C
/* blue */ #include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll,ll> pll; vector<pll> va, vb; const int dx[] = {1,1,-1,-1}; const int dy[] = {1,-1,1,-1}; #define x first #define y second inline ll sqr(ll x) {return x*x;} int main() { ll a,b,c; while(cin>>a>>b>>c) { va.clear(); vb.clear(); for(ll i=0, j=a; i<=a; i++) { while(i*i+j*j>a*a) j--; if(i*i+j*j==a*a) va.push_back(pll(i,j)); } for(ll i=0, j=b; i<=b; i++) { while(i*i+j*j>b*b) j--; if(i*i+j*j==b*b) vb.push_back(pll(i,j)); } for(unsigned i=0; i<va.size(); i++) { for(unsigned j=0; j<vb.size(); j++) { for(int d=0; d<4; d++) { if(sqr(va[i].x-vb[j].x*dx[d]) + sqr(va[i].y-vb[j].y*dy[d]) == c*c) { cout << "0 0" << endl; cout << va[i].x << ‘ ‘ << va[i].y << endl; cout << vb[j].x*dx[d] << ‘ ‘ << vb[j].y*dy[d] << endl; goto bk; } } } } cout << "-1" << endl; bk: continue; } return 0; }
J: http://acm.timus.ru/problem.aspx?space=1&num=2033 水 , 忽略
K: http://acm.timus.ru/problem.aspx?space=1&num=2034
blue :
首先用BFS求出每个结点离r点的距离,用dis[u]来表示u到r的距离
然后用一次dij来求,额外用一个数组mx[u]表示从s点到u点上,距离最短的是多少。
那从点u到点v的递推关系就是: mx[v] = min(max(mx[v],mx[u]), dis[v])
求完dij以后,答案就是mx[t]了
#include <bits/stdc++.h> using namespace std; const int N = 100010; const int INF = 1e9; #define drep(i, l, r) for(int i=l; i<(r); i++) #define MAX(x, y) (x>y?x:y) #define MIN(x, y) (x<y?x:y) #define fi first #define se second typedef pair<int,int> pii; int n, m, s, f, r, mx[N], dis[N], d[N]; bool vis[N]; vector<int> g[N]; void bfs(int s) { memset(vis, 0, sizeof(vis)); queue<pii> que; que.push(pii(s, 0)); while(!que.empty()) { int u = que.front().fi; int l = que.front().se; que.pop(); if(vis[u]) continue; vis[u] = 1; dis[u] = l; for(unsigned i=0; i<g[u].size(); i++) { int &v = g[u][i]; que.push(pii(v, l+1)); } } } int dij(int s, int t) { memset(vis, 0, sizeof(vis)); priority_queue<pii, vector<pii>, greater<pii> > que; drep(i, 1, n+1) d[i] = INF, mx[i] = -1; d[s] = 0; que.push(pii(0, s)); while(!que.empty()) { int u = que.top().se; que.pop(); if(vis[u]) continue; vis[u] = 1; if(mx[u] == -1) mx[u] = dis[u]; else mx[u] = MIN(mx[u], dis[u]); if(u == t) return mx[t]; for(unsigned i=0; i<g[u].size(); i++) { int &v = g[u][i]; if(d[u]+1 <= d[v]) { d[v] = d[u]+1; if(mx[v] == -1) mx[v] = mx[u]; else mx[v] = MAX(mx[v], mx[u]); que.push(pii(d[v], v)); } } } return d[t]; } int main() { #ifdef LOCAL freopen("case.txt","r",stdin); #endif while(scanf("%d%d", &n, &m)!=EOF) { drep(i,1,n+1) g[i].clear(); int u, v; drep(i, 0, m) { scanf("%d%d", &u, &v); g[u].push_back(v); g[v].push_back(u); } scanf("%d%d%d", &s, &f, &r); bfs(r); // drep(i, 1, n+1) cout << dis[i] << ‘ ‘; cout << endl; cout << dij(s, f) << endl; } }
L: http://acm.timus.ru/problem.aspx?space=1&num=2035 水 , 忽略