這分數羞於出口(fuck)
T1 大空魔術
題目:
宇佐見蓮子是一個嚮往太空旅行的大學生。但迫於月面旅行團高額的費用,她暫時放棄了幻想,開
始專心於物理學的研究。
在一次偶然的經歷中,蓮子發現了兩種新的粒子,她將這兩種粒子命名為「粒子 A」和「粒子 B」 。
蓮子發現,兩種粒子在不受外界刺激的情況下可以保持穩態,並且會相互吸引。多個粒子在相互的
吸引力作用下會形成一個有序的序列。
蓮子還發現,當特定種類的兩個粒子以特定方式排列時,給予它們一種特定的刺激,就會發生「互
毀」現象:兩個粒子會發生完全的物質-能量轉換,轉化為大量能量。
經過長時間的研究,蓮子發現了「互毀」現象發生的條件:當前僅當相鄰的兩個粒子呈現:”AB”
或”BB” 的形式時,給予特定刺激後它們才會發生「互毀」 。
現在,蓮子在實驗室中將眾多粒子排成了多個序列,她想通過給予刺激的方式,用這些粒子得到盡
可能多的能量,即留下儘可能少的粒子。
由於粒子會相互吸引,每當相鄰的兩個粒子發生「互毀」後,它們左右兩側的粒子還會拼在一起,
仍然保持一個序列的形態。
但粒子數實在是太多了,於是她找到你,請你幫助她求出最後剩餘粒子數的最小值。
輸入:
第 1 行一個整數 t,代表粒子序列的個數。
第 2∼ t 行,第 i + 1 行包含一個只由字元 'A' 和 'B' 構成的字串 \(s_i\) ,描述了一個粒子序列。
輸出:
一個整數,代表最後剩餘粒子數
樣例:
3
AAA
BABA
AABBBABBBB
3
2
0
解題思路:
對於這個有序序列,我們能刪就刪,儘管有 ABBA這種情況,我們發現會有 兩種刪法,但是它產生的貢獻卻都是一樣的,都是 2,所以我們可以根據這個貪心,列舉子串,### 利用一下棧,然後碰上A就入棧,碰上B就出棧,因為無論什麼情況,造成出棧的一定是有B的子串,所以列舉到最後只需要看一下還剩下多少就OK了,
程式碼:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <cstdlib>
#define inf 0x3f
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){ if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){ x=x*10+ch-'0';ch=getchar();}
return x*f;
}
std::stack<char> s;
int main()
{
int t=read();
while(t--)
{
std::string ch;
std::cin>>ch;
for(int i=0;i<=ch.length();i++)
{
if(ch[i]=='A')
{
s.push(ch[i]);
continue;
}
else if(ch[i]=='B')
{
if(s.empty())
{
s.push(ch[i]);
}
else
{
//char top=s.top();
s.pop();
}
}
}
printf("%d\n",s.size());
}
return 0;
}
T2 夜桜街道
題目描述:
深夜,離開實驗室後,蓮子與好友梅麗相約來到了一條長滿櫻花樹的街道,她們決定從街道的左側
某個位置出發向右走,欣賞沿途的每一棵櫻花。
她們發現,這條街道上共有 n 棵櫻花樹,從左到右的編號依次為 1,2,···n,每一棵櫻花樹都有自
己的美麗值,編號為 i 的櫻花樹的美麗值為\(a_i\)。
蓮子喜歡驚喜的感覺。若她以某個位置作為起點向右走,她看到一棵櫻花樹的驚喜度定義為:從起
點到這棵樹途經的所有樹中,比這棵樹的美麗值小的個數。
梅麗決定用平均值描述蓮子的平均驚喜度。她定義區間 [l,r] 的平均驚喜度為,從櫻花樹 l 開始走,
向右走到櫻花樹 r 時,看到所有櫻花樹的驚喜度之和,除以區間中櫻花樹的個數。
現在,蓮子和梅麗想知道,以櫻花樹 1 為起點,分別以櫻花樹 1 ∼ n 為終點時,蓮子的平均驚喜
度之和。
由於她倆都不喜歡小數,你只需要輸出這個值對 998244353 取模的結果。
輸入:
第 1 行一個整數 n,表示櫻花樹的棵樹。
第 2 行有 n 個整數,第 i 個整數表示編號為 i 的櫻花樹的美麗值\(a_i\)。
輸出:
一行一個整數,表示答案。
樣例:
6
1 1 4 5 1 4
748683269
資料:
對於測試點 1 ∼ 6 ,保證 n ≤ 1000。
對於測試點 1 ∼ 10,保證 n ≤ 5000。
對於測試點 1 ∼ 20,保證 n ≤\(10^6\)。
對於所有測試點,保證 n ≤\(10^6\) ,0 ≤\(a_i\)≤\(2^{30}-1\)。
解題思路:
我們輸入每個\(a_i\)的時候我們可以用樹狀陣列去維護一下它前面的比它小的數,怎麼統計,我們就可以考慮權值樹狀陣列,但是資料開不了,所以需要離散化一下,然後在,如果
離散化的話,就求個順序對,然後,再利用逆元,求解就行了。
程式碼:
未進行離散化的
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <cstdlib>
#define inf 0x3f
#define lowbit(x) x&(-x)
#define int long long
const int maxn=1e6;
const int mod=998244353;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){ if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){ x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n;
int num[maxn],s[maxn],tree[maxn],inv[maxn];
int MAX;
void add(int x,int k)
{
for(int i=x;i<=MAX;i+=lowbit(i))
{
tree[i]++;
}
}
int find(int x)
{
int sum=0;
for(int i=x;i>=1;i-=lowbit(i))
{
sum+=tree[i];
}
return sum;
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)
{
num[i]=read();
MAX=std::max(MAX,num[i]);
}
for (int i = 1; i <= n; i++)
{
s[i]=find(num[i]-1);//小於等於的為 find(num[i]),
//std::cout<<s[i]<<"TEXT"<<std::endl;
add(num[i],1);
}
int ans=0;
inv[1]=1;
/*for(int i=1;i<=n;i++)
{
// -k * r_-1
inv[i]=(-p/i)*inv[p%i];
} */
for(int i=2;i<=n;i++)
{
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
}
for(int i=1;i<=n;i++)
{
s[i]+=s[i-1];
s[i]%=mod;
ans=(ans+inv[i]%mod*s[i])%mod;
ans%=mod;
// std::cout<<inv[i]<<std::endl;
// std::cout<<ans<<std::endl;
}
printf("%lld",ans);
return 0;
}
進行了離散化的
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <cstdlib>
#define inf 0x3f
#define lowbit(x) x&(-x)
#define int long long
const int maxn=1e6;
const int mod=998244353;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){ if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){ x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n;
int num[maxn],s[maxn],tree[maxn],inv[maxn];
int MAX;
void add(int x,int k)
{
for(int i=x;i<=MAX;i+=lowbit(i))
{
tree[i]++;
}
}
int find(int x)
{
int sum=0;
for(int i=x;i>=1;i-=lowbit(i))
{
sum+=tree[i];
}
return sum;
}
int b[maxn];//離散化用的陣列
signed main()
{
n=read();
for(int i=1;i<=n;i++)
{
num[i]=read();
b[i]=num[i];
MAX=std::max(MAX,num[i]);
}
std::sort(b+1,b+n+1);//從小到大排序
int len = std::unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++)
{
num[i]=std::lower_bound(b+1,b+len+1,num[i])-b;
MAX=std::lower_bound(b+1,b+len+1,MAX)-b;
}
for (int i = 1; i <= n; i++)
{
s[i]=find(num[i]-1);//小於等於的為 find(num[i]),
//std::cout<<s[i]<<"TEXT"<<std::endl;
add(num[i],1);
}
int ans=0;
inv[1]=1;
/*for(int i=1;i<=n;i++)
{
// -k * r_-1
inv[i]=(-p/i)*inv[p%i];
} */
for(int i=2;i<=n;i++)
{
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
}
for(int i=1;i<=n;i++)
{
s[i]+=s[i-1];
s[i]%=mod;
ans=(ans+inv[i]%mod*s[i])%mod;
ans%=mod;
// std::cout<<inv[i]<<std::endl;
// std::cout<<ans<<std::endl;
}
printf("%lld",ans);
return 0;
}
T3科學世紀
問題描述:
t 組資料,每次給定整數 p,q,求一個最大的整數 x,滿足 p 可以被 x
整除,並且 q 不能整除 x。
輸入:
第 1 行一個整數 t,代表資料組數。
第 2 ∼ t + 1 行,每行兩個整數 p,q,代表給定的兩個引數。
輸出:
共 t 行,每一行代表對應的 x 的值。
樣例:
輸入:
3
10 4
12 6
179 822
輸出:
10
4
179
思路分析:
顯然,如果 \(p<q\),那麼\(p|x\)的時候,\(p\not|x\),很顯然,\(p\)就符合輸出的條件,那麼我們這個時候輸出p 就好了,同時,\(p\) % \(q\) !=0的時候,也就輸出\(p\)就好了,
那現在就是考慮其他情況的時候,我們考慮一下,\(p\)和\(q\)的質因子,但是\(p\)中有比\(q\)質因子大的,但它對答案並不產生貢獻,我們做的是列舉刪除某個質因子,然後尋求最大值(為什麼要刪去一個,刪去多個就會使得\(x\)下降,導致不是最優解)
所以解法就是 :列舉 \(q\)的每一個質因子,然後令\(p\)去除以它,直到\(p\)中的質因子的數要小於\(q\)中質因子數,然後比較出最大值來,然後就是答案;
總複雜度 O(\(t\sqrt{q}\))
先對 \(p,q\) 質因數分解,設 \(\{a_i\}\) 為質數集,\(\{b_i\}\) 為對應質數的次數:
$$p=\prod a_{i}^{b1_i}$$
$$q=\prod a_{i}^{b2_i}$$
有 \((x|p) \land (q\nmid {x})\),則 \(x\) 質因數分解後有:
$$x=\prod a_{i}^{b3_i}$$
$$p=k\times x =k\times \prod a_{i}^{b3_i}(k\in \mathbf{N}^*)$$
$$∃a_j|q,\ b3_j < b2_j$$
第二個條件表示 \(x|p\),第三個條件表示存在一個整除 \(q\) 的質數 \(a_j\),它在 \(x\) 中的次數比在 \(q\) 中的次數要小,從而使 \(q\nmid x\)。
顯然,最優的 \(x\) 一定是 \(p\) 摳去一些質因子 \(a_j\),使得該質因子在 \(p\) 中的次數小於 \(q\) 中的次數後剩下的值。
顯然摳去的質因子最多有一個。
所以可以列舉 \(q\) 的所有質因子並進行計算。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define int long long
#define INF (1e13 + 7)
#define MANX MAXN
#define MAXN 2000000
using namespace std;
inline int read()
{
int x = 0, f = 1; char c = getchar();
while (c > '9' || c < '0') {if (c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') {x = x * 10 + (c ^ 48); c = getchar();}
return f * x;
}
int a[MAXN], b[MAXN], numa, numb;
signed main()
{
int t = read();
while (t--)
{
int p = read(), q = read();
if (q > p || p % q != 0) {cout << p; puts(""); continue;}//---
int x = p, y = q, ans = 1;//---
for (int i = 2; i <= sqrt(y); i++)
{
if (y % i == 0)
{
numa = 0, numb = 0;
while (x % i == 0) x /= i, numa++;
while (y % i == 0) y /= i, numb++;
int num = numa - numb + 1, k = p;//p的質數的數量減去q質數的數量
for (int j = num; j; j--) k /= i;
ans = max(ans, k);
}
}
if (y != 1)
{
numa = 0, numb = 0;
while (x % y == 0) x /= y, numa++;
numb++;
int num = numa - numb + 1, k = p;
for (int i = num; i; i--) k /= y;
ans = max(ans, k);
}
cout << ans;
puts("");
}
return 0;
}