1007:The Unsolvable Problem
這道題很簡單,是簽到題。題意就是:給定一個數n,有兩個數a,b。使a+b=n。求所有(a,b)組合中a和b最小公倍數的最大值。
思路:1.如果n是奇數的話,那麼結果爲n/2*(n/2+1);2.如果n爲偶數:(1).n/2爲偶數:結果爲(n/2-1)*(n/2+1);(2).n/2爲奇數:結果爲(n/2-2)*(n/2+2);
code:
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <iomanip>
#include <map>
using namespace std;
int main()
{
long long t , n ;
scanf("%I64d" , &t) ;
while(t --)
{
long long sum = 0 ;
scanf("%I64d" , &n) ;
if(n == 2)
printf("1\n") ;
else
{
if(n % 2 == 0)
{
n /= 2 ;
if(n % 2 == 0)
sum = (n - 1) * (n + 1) ;
else
sum = (n - 2) * (n + 2) ;
}
else
{
n /= 2 ;
sum = n * (n + 1) ;
}
printf("%I64d\n" , sum) ;
}
}
return 0;
}
1008:Pieces
這道題是僅次於上一題,但是看了結題報告和標程,還不不太明白,好像是用狀態DP做的,以後重點看一下DP吧~~~
code:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cassert>
using namespace std;
typedef long long int64;
const int MAX_N = 16, INF = ~0U >> 2;
int n;
int dp[1 << MAX_N];
bool can[1 << MAX_N];
char s[MAX_N + 1];
void work() {
scanf("%s", s);
n = strlen(s);
for (int set = 0; set < (1 << n); ++set) {
char cur[MAX_N];
int cnt = 0;
for (int i = 0; i < n; ++i) {
if (set >> i & 1)
cur[cnt++] = s[i];
}
bool check = true;
for (int l = 0, r = cnt - 1; l < r; ++l, --r) {
if (cur[l] != cur[r]) {
check = false;
break;
}
}
can[set] = check;
}
dp[0] = 0;
for (int set = 1; set < (1 << n); ++set) {
dp[set] = INF;
for (int subset = set; subset > 0; (--subset) &= set)
if (can[subset]) {
dp[set] = min(dp[set], dp[set - subset] + 1);
}
}
cout << dp[(1 << n) - 1] << endl;
}
int main() {
int T;
cin >> T;
while (T--) {
work();
}
}
1010:No Pain No Game
這道題一開始就想到暴力求解,但是後來一看數據範圍是50000,果斷TLE了,知道看到結題報告之前也沒想到怎麼做。原來用到了樹狀數組來維護。
思路:求解一個區間的gcd的最大值。把每個數的因子都求出來,然後找到最大值,保證是至少兩個數的約數。然後用樹狀數組。那麼求樹狀數組的方法是什麼麼呢~~用到lowbit(x)函數,就是來計算2^k,其中k是x表示成二進制的末尾0 的個數。code:
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <climits>
#define MAX 50010
using namespace std;
int c[MAX] ;
int n ;
int lowbit(int x)//求2^k
{
return x & (-x) ;
}
void add(int i , int value)//建立樹狀數組
{
while(i <= n)
{
c[i] = max(c[i] , value) ;
i += lowbit(i) ;
}
}
int Max(int i)修改樹狀數組獲得最大值
{
int s = 0 ;
while(i > 0)
{
s = max(s , c[i]) ;
i -= lowbit(i) ;
}
return s ;
}
int a[MAX] , b[MAX] , ans[MAX] ;
struct Node
{
int l , r ;
int index ;
}node[MAX];//建立區間節點
bool cmp(Node a , Node b)
{
return a.l > b.l ;
}
int main()
{
int t , m , l , r ;
scanf("%d" , &t) ;
while(t --)
{
scanf("%d" , &n) ;
int i ;
for(i = 1 ; i <= n ; i ++)
{
scanf("%d" , &a[i]) ;
}
scanf("%d" , &m) ;
for(i = 0 ; i < m ; i ++)
{
scanf("%d%d" , &node[i].l , &node[i].r) ;
node[i].index = i ;
}
sort(node , node + m , cmp) ;
i = n ;
int j = 0 ;
memset(b , 0 , sizeof(a)) ;
memset(c , 0 , sizeof(c)) ;
while(j < m)
{
while(i > 0 && i > node[i].l)
{
for(int k = 1 ; k * k <= a[i] ; k ++ )
{
if(a[i] % k == 0)
{
if(b[k] != 0)
{
add(b[k] , k) ;
}
b[k] = i ;
if(k != (a[i] / k))
{
if(b[a[i] / k] != 0)
{
add(b[a[i] / k] , a[i] / k) ;
}
b[a[i] / k] ;
}
}
}
i -- ;
}
while(j < m && node[j].l > i)
{
ans[node[j].index] = Max(node[j].r) ;
j ++ ;
}
}
for(i = 0 ; i < m ; i ++)
{
printf("%d\n" , ans[i]) ;
}
}
return 0;
}
1011:Sad Love Story
這是一道求最近點對的問題:一個平面上有n個點,開始平明上沒有點,逐個向平面上放點。每次放點都有一個兩點間的最短距離。求放n個點之後最短距離的和是多少。
一開始如果是直接暴力的話會TLE所以採用分治法。
思路:解題過程中採用分治法,從中間向兩邊,過程當中用到了多重集合和迭代器,即multiset和iterator。多重集合就是集合元素可以是重複的。多重集合中lower_bound(P)函數返回值是一個有序的多重集合,元素P的位置。begin()函數返回第一個元素的位置,end()函數返回最後一個元素的位置。然後insert()函數是插入一個元素後自動進行排序。
code:
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <iomanip>
#include <map>
#include <climits>
#include <set>
#include <vector>
#define N 1LL << 60
#define MAX (int)(5e5+10)
using namespace std;
int m[MAX] , u[MAX] ;
void read(int n , int p[])
{
int a , b , c ;
scanf("%d%d%d" , &a , &b , &c) ;
long long cur = 0 ;
for(int i = 0 ; i < n ; ++i)
{
cur = (cur * a + b) % c ;
p[i] = cur ;
}
}
struct point
{
int x , y ;
bool operator<(const point&o)const
{
return x < o.x ;
}
};
void work()
{
long long sum = 0 ;
int n ;
int i , j ;
scanf("%d" , &n) ;
read(n , m) ;
read(n , u) ;
multiset<point>ps ;
long long ans = N ;
for(i = 0 ; i < n ; ++i)
{
point p ;
p.x = m[i] , p.y = u[i] ;
if(i > 0)
{//分治法
multiset<point>::iterator it = ps.lower_bound(p) , e ;
for(e = it ; e != ps.end() ; ++ e)
{
long long dx = e->x - p.x ;
if(dx * dx >= ans)
break ;
long long dy = e->y - p.y ;
ans = min(ans , dx * dx + dy * dy) ;
}
for(e = it ; e != ps.begin() ; )
{
-- e ;
long long dx = e->x - p.x ;
if(dx * dx >= ans)
break ;
long long dy = e->y - p.y ;
ans = min(ans , dx * dx + dy * dy) ;
}
sum += ans ;
}
ps.insert(p) ;
}
printf("%I64d\n" , sum) ;
}
int main()
{
int t ;
scanf("%d" , &t) ;
while(t --)
{
work() ;
}
return 0;
}
這些題還是很好的,會的東西太少了~~還要學很多啊~~好多東西都是聽過但是不太瞭解,或者根本不會寫,加油加油~~~