CF1422
那个博客搭好遥遥无期。
A:
看代码就行。
#include<bits/stdc++.h>
using namespace std;
void work()
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(a < b)swap(a,b);
if(a < c)swap(a,c);
if(a >= b + c)printf("%d\n",a - b - c + 1);
else puts("1");
return;
}
int main()
{
int testcases = 0;
scanf("%d",&testcases);
while(testcases--)work();
return 0;
}
B:
四个对称位置必须相同,必须都改成中位数,还有中间那一行和那一列。
#include<bits/stdc++.h>
using namespace std;
int n,m;
#define MAXN 110
int a[MAXN][MAXN];
bool vis[MAXN][MAXN];
int s[5];
void work()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i)for(int j = 1;j <= m;++j)scanf("%d",&a[i][j]);
long long ans = 0;
for(int i = 1;i <= n / 2;++i)
{
for(int j = 1;j <= m / 2;++j)
{
s[1] = a[i][j];s[2] = a[n - i + 1][j];s[3] = a[i][m - j + 1];s[4] = a[n - i + 1][m - j + 1];
sort(s + 1,s + 1 + 4);
ans += s[2] - s[1] + s[3] - s[2] + s[4] - s[2];
}
}
if(n % 2 == 1)
{
for(int j = 1;j <= m / 2;++j)ans += abs(a[n / 2 + 1][j] - a[n / 2 + 1][m - j + 1]);
}
if(m % 2 == 1)
{
for(int i = 1;i <= n / 2;++i)ans += abs(a[i][m / 2 + 1] - a[n - i + 1][m / 2 + 1]);
}
cout << ans << endl;
return;
}
int main()
{
int testcases = 0;
scanf("%d",&testcases);
while(testcases--)work();
return 0;
}
C:
推式子,就是几个等比数列求和。
#include<bits/stdc++.h>
using namespace std;
char c[100010];
int n;
int a[100010];
#define MOD 1000000007
int power(int a,int b)
{
int res = 1;
while(b > 0)
{
if(b & 1)res = 1ll * res * a % MOD;
a = 1ll * a * a % MOD;
b = b >> 1;
}
return res;
}
int inv(int k){return power(k,MOD - 2);}
int main()
{
scanf("%s",c);
n = strlen(c);
for(int i = 0;i < n;++i)a[n - i] = c[i] - '0';
int ans = 0;
for(int k = 1;k <= n;++k)
{
ans = (ans + 1ll * a[k] * power(10,k - 1) % MOD * (1ll * (n - k + 1) * (n - k) / 2 % MOD) % MOD) % MOD;
int sum1 = 0;
int inv10 = power(10,MOD - 2);
int sum = 1ll * inv10 * inv10 % MOD * (power(inv10,k - 1) - 1) % MOD * inv(inv10 - 1) % MOD;
sum1 = 10ll * (1ll * inv10 * (k - 1) % MOD - sum + MOD) % MOD % MOD * a[k] % MOD * power(10,k - 1) % MOD * power(9,MOD - 2) % MOD;
ans = (ans + sum1) % MOD;
}
cout << ans << endl;
return 0;
}
D:
不妨把起点也看成传送门,那么最后一定是从一个传送门走到终点,可以发现,如果左右走,那么纵坐标是没影响的,因此每个传送门向他上下左右第一个传送门连边跑 \(dijkstra\) 就行了, \(O(n)\) 。
#include<bits/stdc++.h>
using namespace std;
int n,m;
#define MAXN 100010
int sx,sy,fx,fy;
struct pos{int x,y,id;}s[MAXN];
bool cmpx(pos a,pos b){return a.x < b.x;}
bool cmpy(pos a,pos b){return a.y < b.y;}
namespace DIJ
{
struct edge{int to,nxt;long long v;}e[MAXN << 3];
int edgenum = 0,lin[MAXN] = {0};
void add(int a,int b,long long v){e[++edgenum] = (edge){b,lin[a],v};lin[a] = edgenum;return;}
long long d[MAXN];
bool vis[MAXN];
long long dij(int s,int t)
{
memset(d,0x3f,sizeof(d));
d[s] = 0;
priority_queue< pair<long long,int> > q;
q.push(make_pair(0,s));
while(!q.empty())
{
int k = q.top().second;q.pop();
if(vis[k])continue;
vis[k] = true;
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(d[e[i].to] > d[k] + e[i].v)
{
d[e[i].to] = d[k] + e[i].v;
q.push(make_pair(-d[e[i].to],e[i].to));
}
}
}
return d[t];
}
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%d%d%d%d",&sx,&sy,&fx,&fy);
for(int i = 1;i <= m;++i)
{
scanf("%d%d",&s[i].x,&s[i].y);
s[i].id = i;
}
++m;
s[m] = (pos){sx,sy,m};
for(int i = 1;i <= m;++i)DIJ::add(i,m + 1,abs(fx - s[i].x) + abs(fy - s[i].y));
sort(s + 1,s + 1 + m,cmpx);
for(int i = 1;i <= m;++i)
{
if(i - 1 >= 1)DIJ::add(s[i].id,s[i - 1].id,s[i].x - s[i - 1].x);
if(i + 1 <= m)DIJ::add(s[i].id,s[i + 1].id,s[i + 1].x - s[i].x);
}
sort(s + 1,s + 1 + m,cmpy);
for(int i = 1;i <= m;++i)
{
if(i - 1 >= 1)DIJ::add(s[i].id,s[i - 1].id,s[i].y - s[i - 1].y);
if(i + 1 <= m)DIJ::add(s[i].id,s[i + 1].id,s[i + 1].y - s[i].y);
}
cout << DIJ::dij(m,m + 1) << endl;
//for(int i = 1;i <= m + 1;++i)cout << DIJ::d[i] << " ";cout << endl;
return 0;
}
E:
看了题解,一个有趣的 \(DP\) :
如果 \(s[i]\ne s[i+1]\) ,\(dp[i]=s[i]+dp[i+1]\)。
如果 \(s[i]=s[i+1]\) ,\(dp[i]=\min(s[i]+dp[i+1],dp[i+2])\)。
字符串比较大小可以存储 \(2^x\) 长度的哈希值每次求 \(lcp\) 比较下一位。
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
#define MUL 19260817
#define MOD 998244353
int power[MAXN];
struct str{int c,nxt[18],hash[18],len;}s[MAXN];
int scnt = 0;
void build(str &ss,int ch,int nx)
{
ss.c = ch;ss.nxt[0] = nx;ss.len = s[nx].len + 1;
for(int i = 1;(1 << i) <= ss.len;++i)ss.nxt[i] = s[ss.nxt[i - 1]].nxt[i - 1];
for(int i = 0;(1 << i) <= ss.len;++i)ss.hash[i] = ch;
for(int i = 1;(1 << i) <= ss.len;++i)
for(int j = 0,cur = nx;j < i;cur = s[cur].nxt[j],++j)
ss.hash[i] = (1ll * ss.hash[i] * power[1 << j] % MOD + s[cur].hash[j]) % MOD;
return;
}
bool strless(int a,int b)
{
int lcp = 0,l = min(s[a].len,s[b].len);
int cura = a,curb = b;
for(int i = 17;i >= 0;--i)
if(lcp + (1 << i) <= l && s[cura].hash[i] == s[curb].hash[i])
lcp += (1 << i),cura = s[cura].nxt[i],curb = s[curb].nxt[i];
if(lcp == s[a].len && lcp == s[b].len)return false;
if(lcp == s[a].len)return true;
if(lcp == s[b].len)return false;
return s[cura].c < s[curb].c;
}
int strmin(int a,int b){return strless(a,b) ? a : b;}
char ch[MAXN];
int n,dp[MAXN];
void print(int cur)
{
int totl = s[cur].len;
if(totl <= 10)
{
for(;cur != 0;cur = s[cur].nxt[0])putchar(s[cur].c);
}
else
{
for(int i = 1,curp = cur;i <= 5;++i,curp = s[curp].nxt[0])putchar(s[curp].c);
printf("...");
for(int i = 17,pos = totl - 2;i >= 0;--i)if(pos & (1 << i))cur = s[cur].nxt[i];
putchar(s[cur].c);cur = s[cur].nxt[0];putchar(s[cur].c);
}
return;
}
int main()
{
power[0] = 1;for(int i = 1;i < MAXN;++i)power[i] = 1ll * power[i - 1] * MUL % MOD;
scanf("%s",ch + 1);n = strlen(ch + 1);
for(int i = n;i >= 1;--i)
{
if(i + 1 <= n && ch[i] == ch[i + 1])
{
build(s[++scnt],ch[i],dp[i + 1]);
dp[i] = strmin(scnt,dp[i + 2]);
}
else
{
build(s[++scnt],ch[i],dp[i + 1]);
dp[i] = scnt;
}
}
for(int i = 1;i <= n;++i)
{
printf("%d ",s[dp[i]].len);
print(dp[i]);
puts("");
}
return 0;
}
F:
对每个因子维护一个次数的单调栈,在每个位置存储这一个比栈里下一个多的那部分幂,那么对应区间乘积就是 \(\text{lcm}\) ,多次询问用主席树版本维护每个 \(r\) ,下标维护 \(l\) ,每次相当于是插入 \(a[r]\) 。
#include<bits/stdc++.h>
using namespace std;
int n;
#define MAX 200010
#define N 100010
bool isprime[MAX];
int prime[20010],mindiv[MAX],id[MAX];
int a[N];
#define MOD 1000000007
int power(int a,int b)
{
int res = 1;
while(b > 0)
{
if(b & 1)res = 1ll * res * a % MOD;
a = 1ll * a * a % MOD;
b = b >> 1;
}
return res;
}
int inv(int a){return power(a,MOD - 2);}
struct node{int lc,rc,mul;}t[N * 400];
int root[N],ptr = 0;
int newnode(){return ++ptr;}
#define mid ((l + r) >> 1)
void build(int &rt,int l,int r)
{
rt = newnode();t[rt].mul = 1;
if(l == r)return;
build(t[rt].lc,l,mid);
build(t[rt].rc,mid + 1,r);
return;
}
void mul(int &rt,int p,int v,int l,int r)
{//if(l == 1 && r == n)cout << "mul " << p << " " << v << endl;
int nrt = newnode();t[nrt] = t[rt];rt = nrt;
if(l == r){t[rt].mul = 1ll * t[rt].mul * v % MOD;return;}
if(p <= mid)mul(t[rt].lc,p,v,l,mid);
if(p > mid)mul(t[rt].rc,p,v,mid + 1,r);
t[rt].mul = 1ll * t[t[rt].lc].mul * t[t[rt].rc].mul % MOD;
return;
}
int query(int rt,int L,int R,int l,int r)
{
if(L <= l && r <= R)return t[rt].mul;
int res = 1;
if(L <= mid)res = 1ll * res * query(t[rt].lc,L,R,l,mid) % MOD;
if(R > mid)res = 1ll * res * query(t[rt].rc,L,R,mid + 1,r) % MOD;
return res;
}
struct fact{int tim,pos;};
stack<fact> s[20010];
void spop(int fac,int pos)
{
int tim = s[id[fac]].top().tim;
mul(root[pos],s[id[fac]].top().pos,inv(power(fac,tim)),1,n);
s[id[fac]].pop();
if(!s[id[fac]].empty())mul(root[pos],s[id[fac]].top().pos,power(fac,tim),1,n);
return;
}
void spush(int fac,int tim,int pos)
{
if(!s[id[fac]].empty())mul(root[pos],s[id[fac]].top().pos,inv(power(fac,tim)),1,n);
s[id[fac]].push((fact){tim,pos});
mul(root[pos],pos,power(fac,tim),1,n);
return;
}
void insert(int fac,int tim,int pos)
{
while(!s[id[fac]].empty() && tim >= s[id[fac]].top().tim)spop(fac,pos);
spush(fac,tim,pos);
return;
}
int query(int l,int r)
{
return query(root[r],l,r,1,n);
}
int main()
{
for(int i = 2;i < MAX;++i)isprime[i] = true;
for(int i = 2;i < MAX;++i)
{
if(isprime[i])prime[++prime[0]] = i,mindiv[i] = i;
for(int j = 1;j <= prime[0] && i * prime[j] < MAX;++j)
{
isprime[i * prime[j]] = false;
mindiv[i * prime[j]] = prime[j];
if(i % prime[j] == 0)break;
}
}
for(int i = 1;i <= prime[0];++i)id[prime[i]] = i;
scanf("%d",&n);
for(int i = 1;i <= n;++i)scanf("%d",&a[i]);
build(root[0],1,n);
for(int i = 1;i <= n;++i)
{//cout << " : " << i << endl;
root[i] = root[i - 1];
int val = a[i],last = 0,cnt = 0;
while(val != 1)
{
if(mindiv[val] == last)++cnt;
else
{
insert(last,cnt,i);
last = mindiv[val];cnt = 1;
}
val /= mindiv[val];
}
insert(last,cnt,i);
}
int q,a,b,lastans = 0;
scanf("%d",&q);
for(int i = 1;i <= q;++i)
{
scanf("%d%d",&a,&b);
a = (lastans + a) % n + 1;b = (lastans + b) % n + 1;
if(a > b)swap(a,b);
printf("%d\n",lastans = query(a,b));
}
return 0;
}