A-zzy的小號
/*****************************
Author Ms. Wen
Date 2018/4/6
解題思路:
i,l,I,L 等價 遇到任意一個*4
o,O,0 等價 遇到任意一個*3
大小寫字母等價 遇到任意一個*2
*******************************/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int mod = 1e9+7;
char str[1000000];
int main() {
while(~scanf("%s",str)) {
long long ans = 1;
for(int i = 0; i < (int)strlen(str); i++) {
if(str[i]>='a' && str[i]<='z') {
if(str[i]=='l' || str[i]=='i') {
ans = ans*4%mod;
}
else if(str[i]=='o') {
ans = ans*3%mod;
}
else {
ans = ans*2%mod;
}
}
else if(str[i]>='A'&&str[i]<='Z') {
if(str[i]=='I' || str[i]=='L') {
ans = ans*4%mod;
}
else if(str[i]=='O') {
ans = ans*3%mod;
}
else {
ans = ans*2%mod;
}
}
else if(str[i] == '0'&&str[i]<='9') {
ans = ans*3%mod;
}
}
printf("%lld\n",ans);
}
return 0;
}
B-Jxc的軍訓
/*****************************
Author Ms. Wen
Date 2018/4/6
解題思路:
逆向思維,被曬到的概率等於1-不被曬到的概率。
只要站在雲下不管太陽在哪都不會被曬到。則
不被雲曬到的概率爲 m/(n*n)。則被曬到的概率是
(n*n-m)/(n*n)。然後剩餘的就是求乘法逆元的事情
了,由於取模的數爲素數,因此分母fm的乘法逆元
就是fm^(mod-2)。在題目中我們經常看到概率的答案
很大,其實就是因爲這些概率通常牽涉取模,與乘法
逆元有關,不必大驚小怪。
*******************************/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <cmath>
using namespace std;
const int mod = 998244353;
long long qucik(int n,int k) {
long long ans,res;
ans = 1;
res = (long long)n;
while(k) {
if(k&1) {
ans = ans*res%mod;
}
res = res*res%mod;
k = k/2;
}
return ans;
}
int main() {
int n,m;
while(~scanf("%d%d",&n,&m)){
int fz = (n*n-m)%mod;
int fm = (n*n)%mod;
long long ans = fz*qucik(fm,mod-2)%mod;
printf("%lld\n",ans);
}
return 0;
}
C-zzf的好矩陣
/*****************************
Author Ms. Wen
Date 2018/4/6
解題思路:
比如3*3的矩陣,可以通過一定操作放成
1 2 3
4 5 6
7 8 9
由於矩陣中的數字大於0且小於等於n*n,且各個
位置上數不同。則矩陣中的數字必是1~n*n中的數字
各一個。經過菸草發現。1 4 7,2 3 8,3 6 9 .
必是一列。1 2 3,4 5 6,7 8 9,必是一列,因此只要
固定1,2,3的位置,與其綁定的數字必綁定。
1 ,2 ,3的排列數都3!種。橫排的數還可以挑選自己
所處的行,又是3!種。而上例中所有在一行的可以換
成在一列。
1 4 7
2 5 8
3 6 9
因此n*n的矩陣,總共有n!*n!*2种放置方法。
*******************************/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <cmath>
using namespace std;
const int mod = 998244353;
typedef long long ll;
int main() {
int p;
while(~scanf("%d",&p)) {
ll ans = 1;
for(ll i = 1; i <= p; i++) {
ans = ans*i%mod;
}
ans = ans*ans%mod;
ans = ans*2%mod;
printf("%lld\n",ans);
}
return 0;
}
D-applese的生日
/***************************************************************
Author Ms. Wen
Date 2018/4/6
思路:題解上說得挺清楚。
首先有一個結論:每塊蛋糕分成的每一塊的大小是相同的 基於這個結論,
每次找到當前劃分最大塊所在的大塊並將其劃分數+1,檢查是否滿足題目的
要求考慮這個結論爲什麼是正確的考慮一個蛋糕切的刀數不變,那麼可以想
到假如分割得到的塊是不同的,那麼可能的貢 獻是增加最大和最小之間的差
值,那麼這樣答案只會更劣,所以可以想到分成的每個塊的大小是相同的。
*******************************************************************/
#include <iostream>
#include <stdio.h>
#include <map>
using namespace std;
const int maxn = 1005;
double w[maxn];
int divs[maxn]; //蛋糕的分塊數。
multimap<double,int>m; //multimap中key的值可以重複
multimap<double,int>::iterator it1,it2;
int main() {
double t;
int n;
cin>>t>>n;
m.clear();
for(int i = 1; i <= n; i++) {
cin>>w[i];
divs[i] = 1;
m.insert(make_pair(w[i],i));
}
it1 = m.begin();
it2 = --m.end();
int ans = 0;
while(it1->first/it2->first < t) {
int id = it2->second;
divs[id]++;
double aver = w[id]/divs[id];
m.erase(it2);
m.insert(make_pair(aver,id));
it1 = m.begin();
it2 = --m.end();
ans++;
}
printf("%d\n",ans);
return 0;
}
E-VVQ與線段
/**************************************
Author Ms. Wen
Date 2018/4/7
解題思路:
對於所有線段按照左端點從小到大排序。
對於一條選定的線段x1,y1。需要考慮左端點大於等於x1且小於等於y1的
所有線段x2,y2
1.考慮Seg(x2,y2)與Seg(x1,y1)相交但不包含在Seg(x1,y1)中,則異或值
爲(x2+y2)-(x1+y1).由於x1+y1固定,則需要使x2+y2最大。因此建立線段
樹維護所有線段left+right的最大值。
2.考慮Seg(x2,y2)包含在Seg(x1,y1)中,則異或值爲(y1-x1)-(y2-x2)。
由於y1-x1固定,則需要使y2-x2最小,因此建立線段樹維護所有線段right-left
的最小值。
求這兩種情況的最大值。即爲答案。
變量含義:
Max:維護線段left+right最大值的數組
Min:維護線段right-left最小值的數組
s:存放線段信息
方法含義:
push_up1(root):用於更新Max數組的值
push_up2(root):用於更新Min數組的值
build1:構造維護left+right的線段樹
build2:構造維護right-left的線段樹
query1:求與當前線段相交的線段中left+right值最大的。
query2:求與包含在當前線段中的線段中right-left值最小的。
**********************************************************/
#include <iostream>
#include <stdio.h>
#include <algorithm>
#define lchild left,mid,root<<1
#define rchild mid+1,right,root<<1|1
using namespace std;
const int maxn = 200000+4;
int Max[maxn<<2]; //維護線段l+r的最大值
int Min[maxn<<2]; //維護線段r-l的最小值
struct Segment {
int left;
int right;
friend bool operator<(Segment s1,Segment s2) {
return s1.left<s2.left;
}
}s[maxn];
void push_up1(int root) {
Max[root] = max(Max[root<<1],Max[root<<1|1]);
}
void push_up2(int root) {
Min[root] = min(Min[root<<1],Min[root<<1|1]);
}
//維護l+r的最大值,處理相交情況
void build1(int left,int right,int root) {
if(left==right) {
Max[root] = s[left].left + s[left].right;
return;
}
int mid = (left+right)>>1;
build1(lchild); //遞歸構建左右子樹
build1(rchild);
push_up1(root);
}
//維護r-l的最小值,處理包含的情況
void build2(int left,int right,int root){
if(left==right) {
Min[root] = s[left].right - s[left].left;
return;
}
int mid = (left+right)>>1;
build2(lchild);
build2(rchild);
push_up2(root);
}
int query1(int L,int R,int left,int right,int root) {
if(L<=left && right<=R) {
return Max[root];
}
int mid = (left+right)>>1;
int ans = 0;
if(L<=mid) ans = max(ans,query1(L,R,lchild));
if(R>mid) ans = max(ans,query1(L,R,rchild));
return ans;
}
int query2(int L,int R,int left,int right,int root) {
if(L<=left && right<=R) {
return Min[root];
}
int mid = (left+right)>>1;
int ans = 1e8;
if(L<=mid) ans = min(ans,query2(L,R,lchild));
if(R>mid) ans = min(ans,query2(L,R,rchild));
return ans;
}
int main() {
int n,l,r;
while(~scanf("%d",&n)) {
for(int i = 1; i <= n; i++) {
scanf("%d%d",&l,&r);
s[i].left = min(l,r); //防止有l>r的坑
s[i].right = max(l,r);
}
sort(s+1,s+n+1); //按照左端點,從小到大排序。
build1(1,n,1);
build2(1,n,1);
Segment tmp;
tmp.right = 0;
int ans = 0;
for(int i = 1; i <= n; i++) {
tmp.left = s[i].left;
l = lower_bound(s+1,s+n+1,tmp)-s; //尋找左端點>=當前線段的第一條線段
tmp.left = s[i].right;
r = upper_bound(s+1,s+n+1,tmp)-s-1; //尋找左端點>當前右端點的第一條線段。
if(l > r) continue;
//則下標(l,r)內的線段都與當前線段相交或被包含其中。
int num1 = query1(l,r,1,n,1);
int num2 = query2(l,r,1,n,1);
ans = max(ans,num1-(s[i].left+s[i].right));
ans = max(ans,(s[i].right-s[i].left)-num2);
}
printf("%d\n",ans);
}
return 0;
}