A序列划分-codeforces1197C
将非递减的序列划分成k段,使最右减最左的和最小。
和这种序列差值有关的,用差分来写,就转化成和的问题。
B转移矩阵-POJ3070
就是个模板题
#include
#include
using namespace std;
const int MAX = 10;
#define ll long long
class Matrix {
public:
Matrix(int r, int c) :row(r), col(c) {}
void Init()
{
memset(map, 0, sizeof(map));
map[0][0] = map[0][1] = map[1][0] = 1;
}
void Unit() //初始化为单位矩阵
{
memset(map, 0, sizeof(map));
for (int i = 0; i < row; i++)
map[i][i] = 1;
}
int Result() const { return map[0][1] % 10000; }
friend Matrix operator*(const Matrix&, const Matrix&);
int Pow(int);
private:
__int64 map[MAX][MAX];
int row, col;
};
Matrix operator*(const Matrix& M1, const Matrix& M2)
{
Matrix M(M1.row, M2.col);
for (int i = 0; i < M1.row; i++)
for (int j = 0; j < M2.col; j++)
{
M.map[i][j] = 0;
for (int k = 0; k < M1.col; k++)
M.map[i][j] += M1.map[i][k] * M2.map[k][j];
M.map[i][j] %= 10000;
}
return M;
}
Matrix M(2, 2);
int Matrix::Pow(int n)
{
Matrix temp(2, 2);
temp.Init();
for (int i = 0; (1<<i) <= n; i++)
{
if ((1<<i)&n) M = M * temp;
temp = temp * temp;
}
return M.Result();
}
int main()
{
ll num;
while (cin >> num&&num != -1)
{
M.Unit();
cout << M.Pow(num) << endl;
}
return 0;
}
C思维-codeforces797C
感觉思维题,就是贪心,或者由事件的终点来直接推断结果。(个人的一点想法…)
所以这题就是一个贪心,不难,但很容易写错…wa了一个多小时Q-Q
D模拟-OpenJ_Bailian3709
就是个模拟,签到题
#include
#include
#include
#include
using namespace std;
#define ll long long
int main()
{
//freopen("in.txt", "r", stdin);
int n;
scanf("%d", &n);
string temp, ans;
ll tt = 0;
while (n--) {
cin >> temp;
ans.clear();
int size = temp.size();
for (int i = 0; i < size; i++) {//2->10
tt <<= 1;
tt += temp[i] - '0';
}
while (tt) {//10->3
ans.insert(ans.begin(),tt % 3 + '0');
tt /= 3;
}
cout << ans << "\n";
}
}
E最近公共车站-codeforces832D
树上LCA
三个点,两两求LCA,值异或,求出三个点的汇点。(为什么这样能求汇点呢,画图看看就知道了)
G生日序列-HDU4027
线段树,注意当数变为1的时候就不用更新了,因此维护一个最大值的树,是1的时候就不用向下更新。
和codeforces有题挺像的哈
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
const int maxn = 100005;
const int N = 1 << 63;
ll maxx[maxn << 2];
ll sum[maxn << 2];
void pushup(int rt)
{
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
maxx[rt] = max(maxx[rt << 1], maxx[rt << 1 | 1]);
}
void build(int l, int r, int rt)
{
if (l == r)
{
scanf("%lld", &sum[rt]);
maxx[rt] = sum[rt];
return;
}
int m = (l + r) >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
pushup(rt);
}
void update(int L, int R, int l, int r, int rt)
{
if (maxx[rt] <= 1)return;
if (l == r)
{
sum[rt] = (ll)sqrt(1.0*sum[rt]);
maxx[rt] = sum[rt];
return;
}
int m = (l + r) >> 1;
if (L <= m)update(L, R, l, m, rt << 1);
if (m < R) update(L, R, m + 1, r, rt << 1 | 1);
pushup(rt);
}
ll query(int L, int R, int l, int r, int rt)
{
if (L <= l && r <= R)
return sum[rt];
int m = (l + r) >> 1;
ll ret = 0;
if (L <= m) ret += query(L, R, l, m, rt << 1);
if (m < R) ret += query(L, R, m + 1, r, rt << 1 | 1);
return ret;
}
int main()
{
//freopen("in.txt", "r", stdin);
int n;
int cc = 1;
while (scanf("%d", &n) != EOF) {
printf("Case #%d:\n", cc++);
build(1, n, 1);
int m;
scanf("%d", &m);
while (m--) {
int op;
scanf("%d", &op);
if (op == 0) {//update
int l, r;
scanf("%d%d", &l, &r);
if (l > r) {
int temp = l;
l = r;
r = temp;
}
update(l, r, 1, n, 1);
}
else {//sum
int l, r;
scanf("%d%d", &l, &r);
if (l > r) {
int temp = l;
l = r;
r = temp;
}
printf("%lld\n", query(l, r, 1, n, 1));
}
}
printf("\n");
}
}
H超神学院-POJ1703
种类并查集/带权边,我更习惯用带权边来写。
#include
#include
#include
using namespace std;
int pre[100005];
int sum[100005];
int FindLeft(int n) {
if (n == pre[n])
return n;
int r;
r = FindLeft(pre[n]);
sum[n] += sum[pre[n]];
pre[n] = r;
return r;
}
void Link(int i, int j, int s) {
int Prei, Prej;
Prei = FindLeft(i);
Prej = FindLeft(j);
if (Prei < Prej) {
sum[Prej] = s + sum[i] - sum[j];
pre[Prej] = Prei;
}
else {
sum[Prei] = sum[j] - s - sum[i];
pre[Prei] = Prej;
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t;
scanf("%d", &t);
while (t--) {
int n, m;
scanf("%d%d", &n, &m);
memset(sum, 0, sizeof(sum));
for (int i = 0; i <= n; i++)
pre[i] = i;
while (m--) {
char op;
int a, b;
getchar();
scanf("%c %d %d", &op, &a, &b);
if (op == 'D')Link(a, b, 1);
else {
if (FindLeft(a) == FindLeft(b)) {
if ((sum[b] - sum[a]) & 1)printf("In different gangs.\n");
else
printf("In the same gang.\n");
}
else {
printf("Not sure yet.\n");
}
}
}
}
}
I打表题-LightOj-2370
欧拉函数打表题。以前好像写过。
不是打欧拉函数的表,应该也打不下,是打素数的表,因为要满足欧拉函数值尽可能大,且数值尽可能小数,肯定就是素数(在素数an右边an+1左边的合数b,b的欧拉函数值小于等于an的欧拉函数值)
#include
#include
#include
using namespace std;
#define ll long long
const int maxn = 1e6+5;
int prime[maxn];
void init() {//初始化,看这个数是不是素数
memset(prime, 0, sizeof(prime));
prime[0] = prime[1] = 1;
for (int i = 2; i < maxn; i++) {
if (!prime[i]) {
for (int j = i + i; j <= maxn; j += i)prime[j] = 1;
}
}
}
int main()
{
init();
int t;
scanf("%d", &t);
int cnt = 1;
while (t--) {
ll ans = 0;
int n;
scanf("%d", &n);
while (n--) {
int temp;
scanf("%d", &temp);
for (int i = temp + 1;; i++) {
if (prime[i] == 0) {
ans += i;
break;
}
}
}
printf("Case %d: %lld Xukha\n", cnt++, ans);
}
}
J T-shirts Codeforces1000A
就是模拟,没了。