A
题意:每个人有三个值,找出所有满足自己最大的两个值大于所有人最小的两个值的人。
思路:暴力,存所有人最小的值中最大的,和第二小值最大的,分别和每个人最大次大的比较。
Code:
#include <iostream>
#include <cstdio>
#include <algorithm>
#define LL long long
using namespace std;
const int AX = 2e5+66;
struct Node{
int x ,y , z;
}a[AX];
int b[AX];
int c[AX];
int main(){
ios_base::sync_with_stdio(false); cin.tie(0) ; cout.tie(0);
int n ;
cin >> n ;
int x , y , z ;
int tot = 0 ;
int totc = 0 ;
for( int i = 0 ; i < n ; i++ ){
cin >> x >> y >> z;
if( x > y ) swap(x,y);
if( x > z ) swap(x,z);
if( y > z ) swap(y,z);
b[tot++] = x;
c[totc++] = y;
a[i].y = y;
a[i].z = z;
}
int res = 0;
sort( b , b + tot );
sort( c , c + tot );
for( int i = 0 ; i < n ; i++ ){
if( a[i].y >= b[tot-1] && a[i].z >= c[totc-1] ){
res ++;
}
}
cout << res << endl;
return 0 ;
}
B
题意:
设 f(n) 表示 n 的每一位数字的平方之和,求 [a,b] 中有几个 n 满足 k × f(n)=n
思路:18位的数每一位最大是9,平方和加起来不超过1458,直接枚举答案。
Code:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int AX = 1e4+666;
const int MAXN = 1460;
int bit[AX];
LL check( LL x ){
int tp;
LL ans = 0LL;
while( x ){
tp = x % 10;
ans += tp * tp;
x /= 10;
}
return ans ;
}
int main(){
LL k ,a , b;
cin >> k >> a >> b ;
int res = 0;
for( LL i = 0 ; i < MAXN ; i++ ){
LL tmp = (LL)k * i ;
if( tmp >= a && tmp <= b ){
if( check(tmp) == i ){
res ++;
}
}
}
cout << res << endl;
return 0;
}
C
题意:小 Hi 手上有 n 张面值互不相同的钱币,且面值都是 2 的幂次,现在他想知道,他可以组合出多少种小于等于 c 的正整数金额。
思路:组合数学,因为每个数都不同且是2的幂,相当于知道了哪位可以为1,然后对于给出的c,只需要从每次从c当前的最高位枚举,
遇到1的话,可以假设:
当前为0,那么剩下位数中可以为1的可以随便放1或者0,结果都是小于c
当前为1,如果这位可以放1,那么继续枚举,不可以放1的话就结束了。
Code:
#include <bits/stdc++.h>
#define LL unsigned long long
using namespace std;
const int AX = 100;
int num[AX];
int sum[AX];
LL a[AX];
int main(){
ios_base::sync_with_stdio(false); cin.tie(0) ; cout.tie(0);
int n ;
LL c ,x ;
cin >> n >> c;
for( int i = 0 ; i < n ; i++ ){
cin >> x;
for( int j = 0 ; j <= 64 ; j++){
if( (1ULL<<j) & x ){
num[j] ++;
break;
}
}
}
sum[0] = num[0];
for( int i = 1 ; i <= 64 ; i++ ){
sum[i] = sum[i-1] + num[i];
}
/* for( int i = 0 ; i <= 64 ; i++ ){
cout << sum[i] << endl;
}*/
LL tmp = c;
int bit[AX];
int tot = 0;
while( tmp ){
bit[tot++] = tmp % 2;
tmp /= 2 ;
}
LL res = 0ULL;
res = (1ULL<<(sum[tot-2])) - 1 ;
if( num[tot-1] ){
for( int i = tot - 2 ; i >= 0 ; i -- ){
if( !bit[i] ) continue;
res += ( 1ULL<<( (i-1 < 0) ? 0 : sum[i-1]) ) ;
if( !num[i] ){
break;
}
}
}
cout << res << endl;
return 0;
}
E
题意:求每个区间每个数字出现次数的平方*这个数字的和
思路:莫队离线查询。
Code:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int AX = 1e6+666;
LL a[AX];
int b[AX];
struct Node{
int l , r ;
int id ;
bool friend operator < ( const Node &x , const Node &y ){
return b[x.l] == b[y.l] ? x.r < y.r : x.l < y.l ;
}
}s[AX];
LL res[AX];
LL num[AX];
LL ans ;
void solve( int x , int add ){
ans -= x * (LL) num[x] * num[x];
num[x] += add;
ans += x * (LL) num[x] * num[x];
}
int main(){
//ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n , t ;
scanf("%d%d",&n,&t);
for( int i = 1 ; i <= n ; i++ ){
scanf("%I64d",&a[i]);
}
int len = sqrt(n*1.0) ;
for( int i = 1 ; i <= n ; i++ ){
b[i] = ( i - 1 ) / len + 1 ;
}
for( int i = 1 ; i <= t ; i++ ){
scanf("%d%d",&s[i].l,&s[i].r);
s[i].id = i ;
}
sort( s + 1 , s + t + 1 );
ans = 0LL;
int l = 0 , r = 0 ;
for( int i = 1 ; i <= t ; i++ ){
while( l < s[i].l ) solve( a[l++] , -1 ) ;
while( l > s[i].l ) solve( a[--l] , 1 ) ;
while( r < s[i].r ) solve( a[++r] , 1 ) ;
while( r > s[i].r ) solve( a[r--] , -1 ) ;
res[s[i].id] = ans ;
}
for( int i = 1 ; i <= t ; i++ ){
printf("%I64d\n",res[i]);
}
return 0 ;
}
G
题意:求表面积。
思路:我是求出总共的面数减去遮盖的。分别从6个面考虑遮盖。
Code:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int AX = 1e2+66;
int a[AX][AX];
char s[AX][AX];
int n , m;
LL cal( int x , int y ){
LL ans = 0 ;
if( a[x][y] > 1 ){
ans += ( ( a[x][y] - 1 ) * 2 );
}
int x1 = x - 1 ;
int y1 = y - 1 ;
int x2 = x + 1 ;
int y2 = y + 1 ;
if( x1 >= 0 && a[x1][y] ){
ans += min( a[x1][y], a[x][y]) ;
}
if( x2 < n && a[x2][y] ){
ans += min( a[x2][y] , a[x][y] );
}
if( y1 >= 0 && a[x][y1] ){
ans += min( a[x][y1], a[x][y] );
}
if( y2 < m && a[x][y2] ){
ans += min( a[x][y2], a[x][y] );
}
return ans ;
}
int main(){
ios_base::sync_with_stdio(false); cin.tie(0) ; cout.tie(0);
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
cin >> n >> m ;
LL sum = 0LL;
for( int i = 0; i < n ; i++ ){
cin >> s[i];
}
for( int i = 0 ; i < n ; i++ ){
for( int j = 0; j < m ; j++ ){
a[i][j] = s[i][j] - '0';
sum += a[i][j];
}
}
sum *= 6;
for( int i = 0 ; i < n ; i++ ){
for( int j = 0 ; j < m; j++ ){
if( !a[i][j] ) continue;
int ans = cal( i , j );
//cout << ans << endl;
sum -= ans ;
}
}
cout << sum << endl;
return 0;
}
I
题意:给出n个货币,m个汇率转换关系,问能不能通过转换货币从而使任意一种钱币升值。
思路:最长路,汇率有小于1,乘法的小于1相当于加法的负数,所以相当于会有负权,用spfa或者floyd求。
注意:数据由货币自己兑换自己的zz情况。我从每个点搜wa到死。。
Code:
#include <bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int AX = 100+66;
int a[AX];
map<string,int>mp;
int tot ;
double dis[AX][AX];
void floyd(){
for( int k = 1; k <= tot ; k++ ){
for( int i = 1 ; i <= tot ; i++ ){
for( int j = 1 ; j <= tot ; j++ ){
if( dis[i][j] < dis[i][k] * dis[k][j] ){
if( dis[i][k] != -INF && dis[k][j] != -INF ){
dis[i][j] = dis[i][k] * dis[k][j];
}
}
}
}
}
}
int main(){
string s ;
int Case = 0;
int n;
while( scanf("%d",&n) && n ){
tot = 0 ;
mp.clear();
for( int i = 0 ; i < n ; i++ ){
cin >> s;
if( !mp[s] ){
mp[s] = ++tot;
}
}
int m ;
scanf("%d",&m);
string s1,s2;
double d;
for( int i = 0 ; i < AX ; i++ ){
for( int j = 0 ; j < AX ; j++ ){
if( i == j ) dis[i][j] = 1.0;
else dis[i][j] = -INF;
}
}
for( int i = 0 ; i < m; i++ ){
cin >> s1 >> d >>s2;
int u = mp[s1];
int v = mp[s2];
dis[u][v] = d;
}
floyd();
int f = 0 ;
for( int i = 1 ; i <= tot ; i++ ){
if( dis[i][i] > 1.0 ){
f = 1 ;
break;
}
}
cout << "Case "<< ++Case <<": ";
cout << ( f ? "Yes" :"No") <<endl;
}
return 0;
}
K
题意:0操作l,r区间降序,1操作l,r区间升序,最后问k位置
思路:二分答案+线段树维护。
原题Hi~ o( ̄▽ ̄)ブ
Code:
#include <bits/stdc++.h>
using namespace std;
const int AX = 1e5+66;
int lazy[AX<<2];
int s[AX<<2];
int a[AX];
int op[AX];
int l[AX];
int r[AX];
int n,k;
int tot;
void pushDown( int rt , int L , int R ){
if( lazy[rt] != -1 ){
int mid = ( L + R ) >> 1 ;
s[rt<<1] = ( mid - L + 1 ) * lazy[rt] ;
s[rt<<1|1] = ( R - mid ) * lazy[rt];
lazy[rt<<1] = lazy[rt];
lazy[rt<<1|1] = lazy[rt];
lazy[rt] = -1;
}
return ;
}
void pushUp( int rt ){
s[rt] = s[rt<<1] + s[rt<<1|1];
return ;
}
void build( int l , int r , int rt , int v ){
lazy[rt] = -1;
if( l == r ){
s[rt] = ( a[l] > v ) ;
return ;
}
int mid = ( l + r ) >> 1 ;
build( l , mid , rt << 1 , v );
build( mid + 1 , r , rt << 1 | 1 , v);
pushUp(rt);
}
void update( int L , int R , int v , int l , int r , int rt ){
if( L <= l && R >= r ){
s[rt] = v * ( r - l + 1 );
lazy[rt] = v;
return;
}
pushDown(rt,l,r);
int mid = ( l + r ) >> 1;
if( L <= mid ) update( L , R , v , l , mid , rt << 1 );
if( R > mid ) update( L , R , v , mid + 1 , r , rt << 1 | 1);
pushUp(rt);
}
int query( int L , int R , int l , int r , int rt ){
if( L <= l && R >= r ){
return s[rt];
}
pushDown(rt,l,r);
int ans = 0 ;
int mid = ( l + r ) >> 1;
if( L <= mid ) ans += query( L , R , l , mid, rt << 1 );
if( R > mid ) ans += query( L , R , mid + 1, r , rt << 1 | 1 );
return ans ;
}
int main(){
int T;
scanf("%d",&T);
while( T-- ){
memset( s , 0 , sizeof(s) );
int m ;
scanf("%d%d",&n,&m);
for( int i = 1 ; i <= n ; i++ ){
scanf("%d",&a[i]);
}
for( int i = 0 ; i < m ; i++ ){
scanf("%d%d%d",&op[i],&l[i],&r[i]);
}
scanf("%d",&k);
int li = 1 , ri = n ;
while( li < ri ){
int mid = ( li + ri ) >> 1 ;
build( 1 , n , 1 , mid );
for( int i = 0 ; i < m ; i++ ){
int L = l[i];
int R = r[i];
int c = query( L , R , 1 , n , 1 );
update( L , R , 0 , 1 , n , 1 );
if( op[i] ){
if( L <= L + c - 1 ){
update( L , L + c - 1 , 1 , 1, n , 1 );
}
}else{
if( R - c + 1 <= R ){
update( R - c + 1 , R , 1 , 1 , n , 1 );
}
}
}
if( query( k , k , 1 , n , 1 ) ){
li = mid + 1 ;
}else ri = mid ;
}
printf("%d\n",li);
}
return 0 ;
}