A
可以想到,先手必胜的条件是,存在一个奇数。
所以后手想要必胜就需要把所有奇数+1,使其变成偶数。
统计一下奇数的个数即可。
#include
using namespace std;
int main() {
int t;
scanf("%d", &t);
while(t--) {
int n;
scanf("%d", &n);
int cnt = 0;
for(int i = 1; i <= n; i++) {
int v;
scanf("%d", &v);
if(v & 1) cnt++;
}
cout<
B
首先 O(n2) 的计算出所有点之间的距离。
那么问题就转化成了一个基本的最小生成树问题。
#define others
#ifdef poj
#include
#include
#include
#include
#include
#include
#include
#include
#include
#endif // poj
#ifdef others
#include
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
#define eps 1e-8
const double pi = acos(-1.0);
typedef long long LL;
typedef unsigned long long ULL;
void umax(int &a, int b) {
a = max(a, b);
}
void umin(int &a, int b) {
a = min(a, b);
}
int dcmp(double x) {
return fabs(x) <= eps?0:(x > 0?1:-1);
}
void file() {
freopen("data_in.txt", "r", stdin);
freopen("data_out.txt", "w", stdout);
}
namespace solver {
typedef unsigned long long LL;
int n;
struct A {
double x, y, z;
};
struct Edge {
int u, v;
double w;
bool operator < (const Edge & b) const {
return w < b.w;
}
};
double dis(A a, A b) {
return sqrt(pow(a.x-b.x, 2) + pow(a.y-b.y, 2) + pow(a.z - b.z, 2));
}
int fa[5555];
void init() {
for(int i = 0; i < 5555; i++) fa[i] = i;
}
int find(int x) {
return x == fa[x]? x : fa[x] = find(fa[x]);
}
void solve() {
init();
vector V;
vector E;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
double x, y, z;
scanf("%lf%lf%lf", &x, &y, &z);
V.push_back({x, y, z});
}
for(int i = 0; i < n; i++)
for(int j = i + 1; j < n; j++) {
E.push_back({i+1, j+1, dis(V[i], V[j])});
}
sort(all(E));
double ans = 0;
for(int i = 0; i < E.size(); i++) {
int u = E[i].u, v = E[i].v;
double w = E[i].w;
int f1 = find(u), f2 = find(v);
if(f1 == f2) continue;
fa[f1] = f2;
ans += w;
}
printf("%.2f\n", ans);
}
}
int main() {
// file();
int t;
scanf("%d", &t);
while(t--)
solver::solve();
return 0;
}
C
模拟题,每次能召唤的时候贪心的把最强的随从尽可能先召唤出来。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int inf = 1<<30;
const int md = 1e9+7;
int T;
int ans;
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
cin>>T;
while(T--)
{
ans=0;
int x;
priority_queue<int> q;
int n=30;
for(int i=1;i<=3;i++)
{
cin>>x;
q.push(x);
n--;
if(x==0)ans+=1000;
}
int now =0;
for(int i=1;i<=40;i++)
{
if(n)
{
cin>>x;
q.push(x);
n--;
if(x==0)ans+=1000;
}
ans+=now;
if(!q.empty())
{
now+=q.top();
q.pop();
}
}
cout<return 0;
}
D
有向图判环问题,拓扑排序了解一下。
#include
using namespace std;
const int MAXN = 100000 + 16;
const int MAXM = 500000 + 16;
vector<int> G[MAXN];
int D[MAXN];
void init(int n) {
for (int i = 0; i <= n; ++i) {
G[i].clear();
D[i] = 0;
}
}
int n, m;
char buf[32];
bool citrus() {
int cnt = 0;
queue<int> Q;
for (int i = 0; i < n; ++i) if (D[i] == 0) Q.push(i);
while (!Q.empty()) {
int u = Q.front(); Q.pop(); ++cnt;
for (auto v : G[u]) if (--D[v] == 0) Q.push(v);
}
return cnt == n;
}
int main(int argc, char **argv) {
while (~scanf("%d%d", &n, &m)) {
init(n);
unordered_map<string, int> mp;
for (int i = 0; i < n; ++i) {
scanf("%s", buf);
mp[buf] = i;
}
assert(mp.size() == n);
while (m--) {
scanf("%s", buf); int u = mp[buf];
scanf("%s", buf); int v = mp[buf];
assert(u != v);
G[v].push_back(u);
++D[u];
}
if (citrus()) puts("Citrus Saikou!");
else puts("DameDameYo");
}
return 0;
}
E
签到题,模拟下就好了。
#define others
#ifdef poj
#include
#include
#include
#include
#include
#include
#include
#include
#include
#endif // poj
#ifdef others
#include
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
#define eps 1e-8
const double pi = acos(-1.0);
typedef long long LL;
typedef unsigned long long ULL;
void umax(int &a, int b) {
a = max(a, b);
}
void umin(int &a, int b) {
a = min(a, b);
}
int dcmp(double x) {
return fabs(x) <= eps?0:(x > 0?1:-1);
}
void file() {
freopen("data_in.txt", "r", stdin);
freopen("data_out.txt", "w", stdout);
}
namespace solver {
int n;
void solve() {
scanf("%d", &n);
vector<string> res;
int cnt[3] = {0};
int p = 0;
for(int i = 1; i <= n; i++) {
string tmp;
cin >> tmp;
for(int i = 0; i < tmp.size(); i++) {
if(tmp[i] == 'R') cnt[0]++;
else if(tmp[i] == 'Y') cnt[1] ++;
else cnt[2] ++;
}
}
for(int i = 0; i < 3; i++)
p = max(p, cnt[i]);
if(p == cnt[0]) res.push_back("Red");
if(p == cnt[1]) res.push_back("Yellow");
if(p == cnt[2]) res.push_back("Green");
sort(all(res));
for(int i = 0; i < res.size(); i++)
printf("%s%c", res[i].c_str(), i == res.size()-1?'\n':' ');
}
}
int main() {
// file();
int t;
scanf("%d", &t);
while(t--) solver::solve();
return 0;
}
F
考虑以 dp[i] 代表所有末尾数字为 vi 的方案数。
那么有 dp[i]=∑i−1j=1dp[j]|vj<vi 。
我们可以用 n2 去实现这个程序,但是显然无法通过。
所以我们可以用数据结构(如线段树,树状数组)去优化这个问题,每次 dp[i] 都是由一个区间求和得到的,这样我们就可以在 O(nlogn) 的时间复杂度解决这个问题。
#define others
#ifdef poj
#include
#include
#include
#include
#include
#include
#include
#include
#include
#endif // poj
#ifdef others
#include
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
#define eps 1e-8
const double pi = acos(-1.0);
typedef long long LL;
typedef unsigned long long ULL;
void umax(int &a, int b) {
a = max(a, b);
}
void umin(int &a, int b) {
a = min(a, b);
}
int dcmp(double x) {
return fabs(x) <= eps?0:(x > 0?1:-1);
}
void file() {
freopen("data_in.txt", "r", stdin);
freopen("data_out.txt", "w", stdout);
}
namespace solver {
LL n;
const LL mod = 100000007;
const LL maxn = 110000;
LL dp[maxn];
LL C[maxn];
LL lowbit(LL x) {
return x & -x;
}
void add(LL x, LL v) {
for(LL i = x; i < maxn; i+=lowbit(i)) {
C[i] += v;
C[i] %= mod;
}
}
LL ask(LL x) {
LL res = 0;
for(LL i = x; i; i-= lowbit(i))
res += C[i], res %= mod;
return res;
}
void solve() {
memset(C, 0, sizeof C);
LL res = 0;
scanf("%lld", &n);
for(LL i = 1; i <= n; i++) {
LL v;
scanf("%lld", &v);
LL ans = ask(v) + 1;
add(v, ans);
res += ans;
res %= mod;
}
cout<int main() {
// file();
int t;
scanf("%d", &t);
while(t--) solver::solve();
return 0;
}
G
我们考虑倒着做这个问题,让meopass去寻找huge,这是概率DP的一个常用小技巧,对于DP而言其实正着和倒着推导并没什么区别。
用 dp[i] 代表meopass刚到区域 i 花费的时间是多少。
考虑状态转移,现在若 P[i][j] 不为0,那么就可以从 dp[j] 转移到 dp[i] 。
那么对于任意的dp[i]都存在:
dp[i]=∑(1+dp[j])∗P[i][j]|P[i][j]!=0
写成方程的形式就是
dp[i]−∑dp[j]∗P[i][j]|P[i][j]=∑P[i][j]
因为会存在 dp[i] 可以从 dp[j] 推导, dp[j] 也可以从 dp[i] 推导,所以常规的DP不可行。
对此我们可以对 1 到 n 的每个i,列出方程
dp[i]−∑dp[j]∗P[i][j]|P[i][j]=∑P[i][j]
得到了一个方程组,然后令 dp[1]=0 , 用高斯消元法去解这个方程组即可, 答案就是 dp[m] 。
#define others
#ifdef poj
#include
#include
#include
#include
#include
#include
#include
#include
#include
#endif // poj
#ifdef others
#include
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
#define eps 1e-8
const double pi = acos(-1.0);
typedef long long LL;
typedef unsigned long long ULL;
void umax(int &a, int b) {
a = max(a, b);
}
void umin(int &a, int b) {
a = min(a, b);
}
int dcmp(double x) {
return fabs(x) <= eps?0:(x > 0?1:-1);
}
void file() {
freopen("data_in.txt", "r", stdin);
freopen("data_out.txt", "w", stdout);
}
namespace solver {
int n, m;
const int maxn = 111;
double v[maxn][maxn];
double a[maxn][maxn];
int gauss(int n) {
for(int i = 0 ; i < n ; i++){
int r = i;
for(int j = i + 1 ; j < n; j++) if(fabs(a[j][i]) > fabs(a[r][i])) r = j;
/*浮点搞死小圆中找到最大绝对值的系数来消圆本来是为了优化精度,如果在整数的模意义下,这种行为就没有意义了,此时我们只需要找到第i行及以下任意一个系数非零的元来消即可。
for(int j = i ; j < n; j++) if(a[j][i]!=0) { r = j; break;}
*/
if(r != i){
for(int j = 0 ; j <= n ; j++)
swap(a[i][j] , a[r][j]);
}
for(int j = n; j >= i; j--)
for(int k = i + 1; k < n; k++)
a[k][j] -= a[k][i]/a[i][i] * a[i][j];
}//得到上三角矩阵
for(int i = n - 1 ; i >= 0 ; --i){//回带,消元。
for(int j = i + 1 ; j < n ; j++)
a[i][n] -= a[i][j] * a[j][n];
if(a[i][i] < 1e-10 && a[i][n] > 1e-10) return -1;
a[i][n] = a[i][n] / a[i][i];
}
return 1;
}
void solve() {
scanf("%d%d", &n, &m);
m --;
memset(a, 0, sizeof a);
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++)
scanf("%lf", &v[i][j]);
}
for(int i = 1; i < n; i++) {
for(int j = 0; j < n; j++)
a[i][j] -= v[i][j];
a[i][i] = 1;
a[i][n] = 1;
}
a[0][0] = 1;
a[0][n] = 0;
gauss(n);
printf("%.2f\n", a[m][n]);
}
}
int main() {
// file();
int t;
scanf("%d", &t);
while(t--) solver::solve();
return 0;
}
#define others
#ifdef poj
#include
#include
#include
#include
#include
#include
#include
#include
#include
#endif // poj
#ifdef others
#include
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
#define eps 1e-8
const double pi = acos(-1.0);
const int maxn = 1000000 + 10;
long long int a[maxn];
long long int b[maxn];
long long int sum;
int n;
typedef long long LL;
typedef unsigned long long ULL;
void umax(int &a, int b) {
a = max(a, b);
}
void umin(int &a, int b) {
a = min(a, b);
}
int dcmp(double x) {
return fabs(x) <= eps?0:(x > 0?1:-1);
}
void file() {
freopen("data_in.txt", "r", stdin);
freopen("pai_out.txt", "w", stdout);
}
namespace solver {
void solve() {
scanf("%d", &n);
for(int i=0; iscanf("%lld", a+i);
for(int i=0; i1; i++) b[i] = a[i+1] - a[i];
sort(b, b+n-1);
for(int i=1; i1] + b[n-1-i];
sum = 0;
for(int i=0; iprintf("%lld\n", sum);
}
};
int main() {
// file();
int t;
scanf("%d", &t);
while(t--) solver::solve();
return 0;
}
I
贪心的把出现次数最多的字符的权值尽可能分配大即可。
#include
using namespace std;
int arr[27];
bool cmp(int a,int b) {
return a>b;
}
int main()
{
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
string x;
while(cin>>x) {
memset(arr, 0, sizeof arr);
int len = x.size();
for(int i=0; itolower(x[i]),arr[x[i]-'a']++;
sort(arr,arr+26,cmp);
int p = 26;
int ans = 0;
for(int i=0; arr[i]; i++)
ans += p*arr[i],p--;
cout<return 0;
}
J
可以建立线段树对每次询问进行回答。
每个线段树的节点内维护的是一个 5∗5 的矩阵。
对每次询问分成 5 个状态。
0 : 当前子串能组成的目标序列为空
1 : 当前子串能组成的目标序列”2”
2 : 当前子串能组成的目标序列”20”
3 : 当前子串能组成的目标序列”201”
4: 当前子串能组成的目标序列”2018”
令 v[i][j] 代表从状态i转移到状态j需要删除的字符数。
那么合并两颗线段树节点的时候本质就是在进行状态的转移。
状态的转移详见代码。
#include
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long LL;
class Solver {
public:
static const int maxn = 220000;
char str[maxn];
class Seg {
public:
int v[6][6];
Seg operator + (const Seg & b) const {
Seg tmp;
for(int i = 0; i < 5; i++)
for(int j = 0; j < 5; j++)
tmp.v[i][j] = maxn;
for(int i = 0; i < 5; i++)
for(int j = 0; j < 5; j++)
for(int k = 0; k < 5; k++)
tmp.v[i][j] = min(tmp.v[i][j], v[i][k] + b.v[k][j]);
return tmp;
}
} tr[maxn << 2];
void pushup(int rt) {
tr[rt] = tr[rt<<1] + tr[rt<<1|1];
}
void init(Seg & tt) {
for(int i = 0; i < 5; i++)
for(int j = 0; j < 5; j++)
tt.v[i][j] = (i == j? 0 : maxn);
}
void show(Seg x) {
for(int i = 0; i < 5; i++, puts(""))
for(int j = 0; j < 5; j++)
printf("%d ", x.v[i][j]);
}
void build(int l, int r, int rt) {
init(tr[rt]);
if(l == r) {
if(str[l] == '2') tr[rt].v[0][1] = 0, tr[rt].v[0][0] = 1;
if(str[l] == '0') tr[rt].v[1][2] = 0, tr[rt].v[1][1] = 1;
if(str[l] == '1') tr[rt].v[2][3] = 0, tr[rt].v[2][2] = 1;
if(str[l] == '8') tr[rt].v[3][4] = 0, tr[rt].v[3][3] = 1;
if(str[l] == '6') tr[rt].v[3][3] = 1, tr[rt].v[4][4] = 1;
return ;
}
int m = (l + r) >> 1;
if(l <= m) build(l, m, rt<<1);
if(r > m) build(m+1, r, rt<<1|1);
pushup(rt);
}
int n, q;
Seg ask(int L, int R, int l, int r, int rt) {
if(L <= l && R >= r) {
return tr[rt];
}
int m = (l + r) >> 1;
Seg tmp;
init(tmp);
if(L <= m) tmp = tmp + ask(L, R, l, m, rt<<1);
if(R > m) tmp = tmp + ask(L, R, m+1, r, rt<<1|1);
return tmp;
}
void solve() {
scanf("%d%d", &n, &q);
str[0] = 'o';
scanf("%s", str + 1);
build(1, n, 1);
for(int i = 0; i < q; i++) {
int l, r;
scanf("%d%d", &l, &r);
assert(l >= 1 && l <= n);
assert(r >= 1 && r <= n);
int ans = ask(l, r, 1, n, 1).v[0][4];
if(ans >= maxn) puts("-1");
else printf("%d\n", ans);
}
}
} solver;
int main() {
// freopen("data_in.txt", "r", stdin);
// freopen("data_out.txt", "w", stdout);
int t;
scanf("%d", &t);
while(t--) solver.solve();
return 0;
}