目录
A.String
暴力,从最长的开始跑
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
string s;
bool ok(int l,int r){//判断是否是符合要求的串
if(r==l) return 1;
string ss="";
for(int i=l;i<=r;i++) ss+=s[i];
string str=ss;
int x=r-l;
while(x--){
str+=str[0];
str.erase(0,1);
if(str<ss) return 0;
}
return 1;
}
int main()
{
int t;
cin>>t;
while(t--){
cin>>s;
int lr=s.size();
int l=0,r=lr-1;
while(1){
for(int i=r;i>=l;i--){//从长度最大的开始跑
if(ok(l,i)){
for(int j=l;j<=i;j++) cout<<s[j];
cout<<' ';
l=i+1;
r=lr-1;
break;
}
}
if(l>=lr) break;
}
cout<<endl;
}
return 0;
}
B.Irreducible Polynomial
代数基本定理,实数域内是否可拆分成低次幂的乘积
#include<cstdio>
int main() {
int n,tp,a[25];
int cas;
scanf("%d", &cas);
while(cas --) {
scanf("%d", &n);
for(int i=0; i<=n; scanf("%d",a+i),i++);
if(n>2||n==2&&a[1]*a[1]>=4*a[0]*a[2])
printf("No\n");
else
printf("Yes\n");
}
return 0;
}
C.Governing sand
权值线段树+离散化+前缀和,按价值建树,离散化高度,按高度从低到高把每个高度插进去,枚举以每一个高度为最高的树需要的花费(比这个高度高的所有树的花费,(利用前缀和计算)+高度比这个高度低的所有树里,每次贪心选取最小的花费砍树,使得这些低的树的个数总和小于这个高度的树)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
const int maxn = 1e5+10;
ll sum[maxn], b[maxn];
const ll inf = 0x3f3f3f3f3f3f3f3f;
ll ans;
#define rl (rt<<1)
#define rr (rt<<1|1)
#define imid ll mid = (l+r)>>1;
struct trees{
ll p, sum;//p是个数,sum是价值总和
}tree[210<<2];
struct node{
ll h, c, p;//h高度,c价值,p个数
bool operator < (const node &a){//按高度排序
return h < a.h;
}
}nd[maxn];
ll query(ll x, ll l, ll r, ll rt){//查询砍掉前x棵树需要的最小代价,先找左子树再找右子树
if(tree[rt].p == x) return tree[rt].sum;
if(l == r) return x * l;
imid
if(tree[rl].p >= x) return query(x, l, mid, rl);
return tree[rl].sum + query(x-tree[rl].p, mid+1, r, rr);
}
void update(ll x, ll y, ll l, ll r, ll rt){//单点更新,价值为x的点插入y棵树
if(l == r && l == x){
tree[rt].p += y;
tree[rt].sum += y*x;
return;
}
imid
if(x <= mid) update(x, y, l, mid, rl);
else update(x, y, mid+1, r, rr);
tree[rt].p = tree[rl].p + tree[rr].p;
tree[rt].sum = tree[rl].sum + tree[rr].sum;
}
int main()
{
while(~scanf("%d", &n)){
for(int i = 0; i < n; i++){
cin >> nd[i].h >> nd[i].c >> nd[i].p;
b[i] = nd[i].h;
}
//离散化高度
sort(b, b+n);
int k = unique(b, b+n) - b;
for(int i = 0; i < n; i++) nd[i].h = lower_bound(b, b+k, nd[i].h) - b + 1;
//求高度的前缀和
sort(nd, nd+n);
memset(sum, 0, sizeof sum);
for(int i = 0; i < n; i++) sum[nd[i].h] += nd[i].c * nd[i].p;
for(int i = 2; i <= k; i++) sum[i] += sum[i-1];
nd[n].h = k+10;//最大的高度也需要判断一下
memset(tree, 0, sizeof tree);
ans = inf;
ll t = 1, y = 0, cnt = 0;
for(int i = 0; i <= n; i++){
if(nd[i].h > t){
cnt = sum[k] - sum[t];//所有大于此高度的树都被砍掉
if(tree[1].p >= y) cnt += query(tree[1].p - y + 1, 1, 200, 1);
//砍去低的树使得这个高度占一般以上
ans = min(ans, cnt);
y = 0;
for(int j = i-1; nd[j].h == t; j--) update(nd[j].c, nd[j].p, 1, 200, 1);
t++;
}
if(nd[i].h == t) y+=nd[i].p;
}
printf("%lld\n", ans);
}
return 0;
}
D.Number
简单思维题
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
string m;
cin >> n >> m;
int x = m.size();
if(x > n) cout << "T_T" << endl;
else{
cout << m;
n -= x;
while(n--) cout << 0;
cout << endl;
}
return 0;
}
E.Number
线段树+离散化,把区间离散化,把[l, r] 离散化成 [l, r+1),,避免合并区间的时候出错,跟平常的线段树还是有不一样的吧,因为平时叶节点存的是单点,这个线段树存的是小区间
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rl (rt<<1)
#define rr (rt<<1|1)
#define imid int mid = (l+r)>>1;
int n;
const int maxn = 4e5+10;
int x[maxn], y[maxn], l[maxn], r[maxn], s[maxn<<1];
struct node{
int l, r, x, num, lz;
//x是这个区间包含了多少个数(r-l),num是区间被添加了多少次,只对叶节点有用,lz是延迟标记
ll s;//s记录区间里加了多少个数
}tree[maxn<<3];
void build(int l, int r, int rt){//初始化
if(l == r){
tree[rt].l = s[l], tree[rt].r = s[l+1];
tree[rt].x = s[l+1] - s[l];
return;
}
imid
build(l, mid, rl);
build(mid+1, r, rr);
tree[rt].l = tree[rl].l, tree[rt].r = tree[rr].r;
tree[rt].x = tree[rt].r - tree[rt].l;
}
void down(int rt){//标记下推
if(tree[rt].lz){
tree[rl].lz += tree[rt].lz;
tree[rr].lz += tree[rt].lz;
tree[rl].s += 1LL*tree[rt].lz * tree[rl].x;
tree[rr].s += 1LL*tree[rt].lz * tree[rr].x;
tree[rl].num += tree[rt].lz;
tree[rr].num += tree[rt].lz;
tree[rt].lz = 0;
}
}
void update(int x, int y, int rt){//更新
if(x <= tree[rt].l && tree[rt].r <= y){
tree[rt].lz++;
tree[rt].num++;
tree[rt].s += 1LL*tree[rt].x;
return;
}
down(rt);
if(x < tree[rl].r) update(x, y, rl);//不能加等号,因为tree[rl].r是开的,不属于这个区间
if(y > tree[rr].l) update(x, y, rr);
tree[rt].s = tree[rl].s + tree[rr].s;
tree[rt].num = tree[rl].num + tree[rr].num;
}
ll query(ll x, int l, int r, int rt){//查询
if(l == r){
ll t = x%tree[rt].num? x/tree[rt].num+1: x/tree[rt].num;
return t + tree[rt].l - 1;
}
down(rt);
imid
if(tree[rl].s >= x) return query(x, l, mid, rl);
else return query(x-tree[rl].s, mid+1, r, rr);
}
int main()
{
memset(tree, 0, sizeof(tree));
scanf("%d", &n);
int a1, b1, c1, m1, a2, b2, c2, m2;
scanf("%d %d %d %d %d %d %d %d %d %d %d %d", &x[1], &x[2], &a1, &b1, &c1, &m1, &y[1], &y[2], &a2, &b2, &c2, &m2);
int cnt = 0;
for(int i = 1; i <= n; i++){
if(i > 2){
x[i] = (1LL*a1 * x[i-1] + 1LL*b1 * x[i-2] + c1) % m1;
y[i] = (1LL*a2 * y[i-1] + 1LL*b2 * y[i-2] + c2) % m2;
}
l[i] = min(x[i], y[i]) + 1, r[i] = max(x[i], y[i]) + 2;//右区间开放
s[++cnt] = l[i], s[++cnt] = r[i];
}
sort(s+1, s+cnt+1);//离散化
cnt = unique(s+1, s+cnt+1) - (s+1);
build(1, cnt-1, 1);
ll ans = 0;
for(int i = 1; i <= n; i++){
update(l[i], r[i], 1);
ans += r[i] - l[i];
printf("%lld\n", query((ans + 1)>>1, 1, cnt-1, 1));
}
return 0;
}
H.Pair
数位dp,就把十进制改成二进制,从高到低判断两个数的大小
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[33][4][4][3][3];
ll n1[33], n2[33], n3[33];
//pos是位数,x1和x2表示状态,1可以,2不行,0不确定,l1和l2表示当前位数的数字有没有限制
ll dfs(int pos, int x1, int x2, bool l1, bool l2){
if(pos == -1) return x1 == 1 || x2 == 1;
if(x1 == 2 && x2 == 2) return 0;//都不行直接退出
if(dp[pos][x1][x2][l1][l2] != -1) return dp[pos][x1][x2][l1][l2];
int up1 = l1? n1[pos]: 1, up2 = l2? n2[pos]: 1;
ll ans = 0;
for(int i = 0; i <= up1; i++){
for(int j = 0; j <= up2; j++){
int p = x1, q = x2;
if((i & j) > n3[pos] && x1 != 2) p = 1;
if((i & j) < n3[pos] && x1 != 1) p = 2;
if((i ^ j) < n3[pos] && x2 != 2) q = 1;
if((i ^ j) > n3[pos] && x2 != 1) q = 2;
ans += dfs(pos-1, p, q, l1&&i==up1, l2&&j==up2);
}
}
dp[pos][x1][x2][l1][l2] = ans;
//函数里没有区分有没有限制,因为每次的dp值都不一样,同样的位数不可能重复,
//之前的数为dp的结果都是一样的,只是查询的区间不一样,所以会分有没有限制
return ans;
}
ll solve(ll a, ll b, ll c){
int p1 = 0, p2 = 0, p3 = 0;
memset(n1, 0, sizeof n1);
memset(n2, 0, sizeof n2);
memset(n3, 0, sizeof n3);
while(a){
n1[p1++] = a % 2;
a>>=1;
}
while(b){
n2[p2++] = b % 2;
b>>=1;
}
while(c){
n3[p3++] = c % 2;
c>>=1;
}
return dfs(max(p1, max(p2, p3))-1, 0, 0, 1, 1);
}
int main()
{
int t;
cin >> t;
while(t--){
ll a, b, c;
memset(dp, -1, sizeof dp);
cin >> a >> b >> c;
cout << solve(a, b, c) - min(a, c-1) - min(b, c-1) -1 << endl;
}
return 0;
}
J.A+B problem
把输入的数倒过来求和,再把和倒过来输出
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int t;
cin>>t;
while(t--){
string a,b;
cin>>a>>b;
ll x=0,y=0;
reverse(a.begin(),a.end());
reverse(b.begin(),b.end());
ll z=0;
for(int i=0;i<a.size();i++){
x=x*10+a[i]-'0';
}
for(int i=0;i<b.size();i++){
y=y*10+b[i]-'0';
}
z=x+y;
if(!z) cout<<z<<endl;
else{
while(z%10==0) z/=10;
while(z){
cout<<z%10;
z/=10;
}
cout<<endl;
}
}
return 0;
}