后续目标代码写在solve()方法中
#include
//#include
//#include
//#include
//#include
//#include
using namespace std;
#define ll long long
#define endl "\n"
const int N = 2e5 + 10;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int INF = 1e9;
const int MAXN = 2020;
const int mod = 1e8 + 7;
int prime[N];
void check() {
memset(prime, 0, sizeof(prime)); //0 素数 1 不是素数
prime[1] = 1;
for (int i = 2; i <= N; i++) {
if (prime[i] == 0) {
for (int j = i * 2; j <= N; j += i) {
prime[j] = 1;
}
}
}
}
bool cmp(int x, int y) {
return x > y;
}
void solve() {
}
int main() {
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t;
cin >> t;
// cin.ignore() ;
// cin.clear();
//t = 1;
//check();
//这里根据具体情况来变动t,是输入还是默认为1
while ( t--) {
solve();
}
}
大小比较即可,如果数字很大,可以进行高精度大小比较即可
//这里直接给高精度模板了,低精度无意义
void solve() {
string s1,s2;
cin>>s1>>s2;
int len_s1=s1.size();
int len_s2=s2.size();
if(len_s1!=len_s2){
cout<<(len_s1>len_s2?"kou":"yukari")<s2[i]?"kou":"yukari")<
模拟即可,每天如果白天没做梦就进行转移获得最大幸福度,否则就正常计算
//正常逻辑判断即可
void solve() {
int n;
cin >> n;
string day, night;
cin >> day >> night;
int ans = 0;
for (int i = 0; i < n; i++) {
if (day[i] == 'N') {
ans += (night[i] == 'Y' ? 2 : 0);
} else {
ans += (2 + ((night[i] == 'Y') ? 1 : 0));
}
}
cout << ans << endl;
}
利用find函数寻找子串即可,然后对该子串进行bool处理,随后依次输出即可
void solve() {
string s;
cin>>s;
vectorb(s.size());
for(int i=0;i
先进行题目规律的探索,去寻找规律,即明显应该排完序后再看,如果去除几号元素,会发生中位数变化有什么规律,同时可以发现将数据分成奇偶来考虑,同时对半分进行考虑即可
struct data{
double value;
int pos;
int pos_sort;
};
bool cmp( struct data x,struct data y) {
return x.value > y.value;
}
void solve() {
int n;
cin>>n;
//为更好处理下标问题,可以选择牺牲一个单位空间进行处理
vectora(n+1),b(n+1);
vectorans(n+1);
for(int i=1;i<=n;i++) {cin>>a[i]; b[i]=a[i];}
//利用一个额外vector来记忆原来顺序即可
//两种常见解法,一种利用中值判断即可
sort(a.begin(),a.end());
//排序后得到中间值,利用中间值来判断即可
if(n%2==0){//偶数情况下 如 1 2 3 4 5 6 6/2=3
int midNum1=a[n/2];
int midNum2=a[n/2+1];
for(int i=1;i<=n;i++){
//这里其实考虑了相等的情况,可以证明
if(b[i]>mid[i].value; mid[i].pos=i;}
// sort(mid+1,mid+n+1,cmp);
// for(int i=1;i<=n;i++){ mid[i].pos_sort=i;}
//后续处理与上面一致,无需再复杂化,只不过如果想构建,得用结构体才行
}
此题特别注意数据范围,数据大问题
题目首先进行第一步直观的操作就是要得到一个数的全部质因数,及其对应的个数,这一步我们可以联想到欧式筛选法进行套用,便可以完成
第二步问题在于,我们应该如何去构建这个数组,即如何从数学上保证该数组满足条件,那么最开始我们可以想到的是利用每一次取两个最多的各一个,但这种我们没法去证明,只能模糊的得到当最多的个数>其余总和+1的情况是绝对不满足的,但我们无法证明其相反面是满足的,所以这里我们进一步采用填补法,插空法来论证,因为要求有相邻不同,排列那么很明显用插空法的思想来论证是比较好的,所以我们来采用一种构造方式
我们将最多的质因数先排列,然后第二多的去插空,可以发现,只要最多的n个的n-1个空被插满了,那么就肯定可以构造成功,后续的空是越来越多的,所以论证完毕
#define pii pair
#define pll pair
//#define int long long 一般不启用 如果启用那么main那里需要要改signed
bool cmp( pii x, pii y) {
return x.first > y.first;
}
void solve() {
//用一个pll来存储即可,map也行,但无需去排序处理,避免浪费时间
vectora;
//因为任何合数一定可以拆解成质因数,所以我们从小的数开始去逐渐拆解即可
ll x; //10^19
cin >> x;
//处理前,需要去特判一下,可以看到下面的循环是x从4开始的,所以可以对x<4进行处理即可
//同时由于x=2,3可以在后续处理掉,所以这里不进行特判
if(x==1){
cout<<-1< 1) a.push_back({1, x}), sum += 1; //当x=2,3是也可以这样处理
sort(a.begin(),a.end(),cmp);
//或者第三个参数为 greater()
if(a[0].first*2>sum+1){ //插空法判断 sum-n>=n-1才行
cout<<-1<ans(sum);
//然后依次隔空放即可
ll j=0;
for(ll i=0;i
题目的知识点进行分解理解,首先是分数取模问题,即逆元问题
x/y 对p取模 本质上就是x*y对p的逆元后再对p取模
(x/y)%p=a a**y%p=x ->
a X y X y^-1 %p=x X y^-1 %p -> a%p=x * y^-1 %p
所以这里就可以得到所谓的求x/y对p取模本质上就是x*y对p的逆元后%p
所以求a,问题在于求y对p的逆元,这里采用最简单的费马小定理和欧拉定理得到的编程实现
结合带mod的快速幂算法和求逆元算法,注意前提条件一定是y,p是互质的,通常取p是素数,即费马小定理这个特殊情况下,才可以运用这个快速幂模版来计算
由于概率是分数,我们就不能够进行直接相除之后再转化,不然那样会失真,所以我们需要将/完全转化为%操作,也就是(1-dpi-1,j+mod)%mod操作 将概率进行取模化
其次DP问题,我在代码注释里进行了更加详细的解释
//如果存在某一堆石子为2 必然使用技能1
//如果不存在某一堆石子为2 必然使用技能2,此时胜率为100%
//考虑到彼此之间存在特殊的关系,即小红进行操作时,如果石子全为1,则使用技能2必胜
//如果不全为1,则使用技能1,但是使用是有取舍选择的,显然是两种选择,1种是选择堆为2的石子,消去一个,或者是选择堆为1的石子让其消失
//同时,选择的概率也取决于当时的状态 所以明显需要使用到状态转移,动态规划进行考虑
//故设置dp[i][j] 表征当前有i个石子数为1的堆,j个石子数为2的堆,此时先手方(小红)的获胜概率
//i+j堆石子 那么 i/(i+j)的概率选择到消去1个石头 j/(i+j)的概率选择到消去2个石头中的1个石头
//所以状态转移就出来了 dp[i][j]=dp[i+1][j-1]*j/(i+j)+dp[i-1][j]*i/(i+j)
//然后可以知道 dp[i][0]=1 然后进行状态转移dp即可
//这里存在一个问题,那就是动态规划必须是底层向前层推进,不可推进过程中收到之前的影响
//如果这里设置 i,j i表示堆为1的石子 那这样必然存在互相影响,因为转移只能i从小到大
//而这里的i,j状态中i,j需要i+1层,所以肯定有问题
//这里进行转化即可,i重新定义为全部的石子的堆数即可
//dp[i][j]=dp[i-1][j]*(i-j)/i+dp[i][j-1]*j/i;
//这里由于参照了数论中的取模运算,那么对最后的分数取模,我们在同步计算是就必须将/进行转化
//更详细解释参考其他文档
ll qkpow(ll a,ll b){
ll res=1;
ll mul=a%mod;
while(b){
if(b&1) res=res*mul%mod;
b>>=1;
mul=mul*mul%mod;
}
return res;
}
ll getInv(ll x){
return qkpow(x,mod-2);
}
ll dp[MAXN][MAXN]={0};
void solve() {
int n;
cin>>n;
int num[3]={0};
for(int i=0,x;i>x;
num[x]++;
}
//有误!!!不删除进行对比
// for(int i=1;i<=n;i++) dp[i][0]=1;
// for(int i=0;i<=n;i++){
// for(int j=1;j<=n;j++){
// if(i!=0) dp[i][j]=((1-dp[i-1][j]+mod)%mod)*i*getInv(i+j)%mod+((1-dp[i+1][j-1]%mod))*j*getInv(i+j)%mod;
// else dp[i][j]=((1-dp[i+1][j-1]+mod)%mod)*j*getInv(i+j)%mod;
// dp[i][j]%=mod;
// }
// }
for(int i=1;i<=n;i++){
dp[i][0]=1;
for(int j=1;j<=i;j++){
//同时这里的mod一定要完全%化 不然要出问题的
//(1-dp[i-1][j]+mod)%mod) 这一步操作是将概率进行取模化
//(i-j)*getInv(i)%mod)%mod getInv本身就很大所以需要去%一次 在计算完后再进行%mod一次
//这里1减必须要注意,因为我们要考虑谁来操作,那么这一步获胜一定是在前面一人前面一步失败的基础上
dp[i][j]=((1-dp[i-1][j]+mod)%mod)*((i-j)*getInv(i)%mod)%mod+((1-dp[i][j-1]+mod)%mod)*(j*getInv(i)%mod)%mod;
dp[i][j]%=mod;//两个已经%mod的数同样需要再次%mod一次
}
}
cout<