石油大没答案太难受了,上去开了个 c 题结果不会,还特别想弄懂了,网上还没题解,我强迫症要犯了。。
问题A:GCD
时间限制: 1 Sec 内存限制: 512 MB
题目描述
最大公约数GCD(a,b)是指a,b共有的因子中最大的那一个。比如说,GCD(12,18)=6,因为6既是12的因子,也是18的因子,而且不存在其他比6大的而且也是12,18的因子的数。
小明想知道如果给定n,m,对于1<=i<=n,GCD(i,m)的最大值是多少。
输入
第一行有两个用空格隔开的正整数n,m,含义见题目描述
输出
一行,只有一个整数,表示对于1<=i<=n,GCD(i,m)的最大值。
样例输入 Copy
【样例1】
4 6
【样例2】
5 10
样例输出 Copy
【样例1】
3
【样例2】
5
提示
样例1说明
可以按照GCD的定义求得GCD(1,6)=1 ;GCD(2,6)=2;GCD(3,6)=3;GCD(4,6)=2;所以答案为3
样例2说明
可以按照GCD的定义求得GCD(1,10)=1;GCD(2,10)=2;GCD(3,10)=1;GCD(4,10)=2;GCD(5,10)=5,所以答案为5
数据范围
对于60%的数据, 1<=n<=1000,1<=m<=1000
对于100%的数据,1<=n<=1e9,1<=m<=1e9
先求 m 的约数,让后gcd肯定在m的约数中产生,找到 <= n 的最大数即可。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;
int n,m;
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
cin>>n>>m;
vector<int>v;
for(int i=1;i<=m/i;i++)
if(m%i==0)
{
v.push_back(i);
if(1ll*i*i!=m) v.push_back(m/i);
}
sort(v.begin(),v.end());
int pos=lower_bound(v.begin(),v.end(),n)-v.begin();
if(pos==v.size())
printf("%d\n",m);
else
{
if(v[pos]>n) pos--;
printf("%d\n",v[pos]);
}
return 0;
}
问题 E: majSoul
时间限制: 1 Sec 内存限制: 128 MB
题目描述
Bob最近沉迷于“雀魂”麻将,然而当他想做国士无双时却屡屡被断幺九截胡,所以他觉得事有蹊跷,于是复盘了一些玩家的手牌,看看他们有没有作弊。
Bob拿到的手牌是以字符串的形式给出的,字符串中依次给出了每一张牌的内容,每一张牌由两个字符构成,其规则如下:
1.麻将中一共有3*9+7=34种牌:
一条到九条,用t1到t9表示
一饼到九饼,用b1到b9表示
一万到九万,用w1到w9表示
东南西北中发白,分别用y1到y7表示
2.每种牌最多有四个
3.每个人有且仅有十三张牌
输入
第1行1个正整数n(1≤n≤10000),表示有多少副手牌
第2行到第n+1行每行一个字符串s,表示手牌,字符串长度|s|≤1000
输出
n行
对于每副手牌,如果符合规则,就输出yes,否则输出no
样例输入 Copy
6
t1t9b1b9w1w9y1y2y3y4y5y6y7
t1t2t3t4t5t6t7t8t9y1y2y3y4
t111t2t3t4t5t6t7t8t9y1y2y3y4
t1t1t1t2t2t2t3t4t5t6t7t8t9
t1t1t1t1t2t2t2t2t3t4t5t6t7
b1b1b2b2b3b3b4b4b5b5b6b6b7b7b8b8b9b9
样例输出 Copy
yes
yes
no
yes
yes
no
提示
说明
第三副牌中t111不是一张有效的牌,不在34种牌内
第六副牌有18张手牌
对于k%的数据,n≤10000∗(k/100)
简单的模拟。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;
int n;
bool check(string s,int l)
{
if(l/2!=13) return true;
vector<int>v[300];
char a='t',b='b',c='w',d='y';
for(int i=0;i<l;i+=2)
{
if(s[i]!=a&&s[i]!=b&&s[i]!=c&&s[i]!=d)
return true;
if(s[i+1]<='0'||s[i+1]>'9') return true;
v[s[i]].push_back(s[i+1]-'0');
}
map<int,int>mp[5];
for(int i=0;i<v[a].size();i++)
{
int t=v[a][i];
if(mp[0][t]==4) return true;
if(t>9||t<1) return true;
mp[0][t]++;
}
for(int i=0;i<v[b].size();i++)
{
int t=v[b][i];
if(mp[1][t]==4) return true;
if(t>9||t<1) return true;
mp[1][t]++;
}
for(int i=0;i<v[c].size();i++)
{
int t=v[c][i];
if(mp[2][t]==4) return true;
if(t>9||t<1) return true;
mp[2][t]++;
}
for(int i=0;i<v[d].size();i++)
{
int t=v[d][i];
if(mp[3][t]==4) return true;
if(t>7||t<1) return true;
mp[3][t]++;
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
while(n--)
{
string s;
cin>>s;
int l=s.length();
if(check(s,l))
puts("no");
else puts("yes");
}
return 0;
}
问题 F: read
时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
Carol是一个爱学习的小朋友,他最近在读一本书,这本书的某些页十分晦涩难懂,需要阅读完另一页的内容才能完全理解。
而有些页则比较通俗易懂,阅读完当前页即可理解。
Carol是一个喜欢钻研的小朋友,他每天都会从这本书中页数最小的从未读过的一页开始读,读到完全理解这一页的内容为止。
例如对于当Carol某一天要读这本书的第a页时,这一页要求读完第b页才能理解,于是Carol又要去读第b页,而第b页要求读完第c页才能理解,于是Carol又要去读第c页,而第c页不需要读别的页就可以理解,或是需要读的页在之前已经读过了,最终Carol这一天读了a,b,c这三页内容。
Carol想知道自己需要花多少天才能读完这本书。
输入
第一行一个整数n,表示这本书有n页
第二行有n个正整数a1,a2,…,an,其中ai表示要读完第i页的内容要先读完第ai页的内容。(ai≥i)
输出
一个正整数,表示读完这本书需要的时间。
样例输入 Copy
【样例1】
6
1 3 3 5 6 6
【样例2】
10
3 4 3 4 8 7 8 10 10 10
样例输出 Copy
【样例1】
3
【样例2】
5
提示
样例1解释:
第一天Carol读了第一页,不需要再阅读其他页。
第二天Carol读了第二页,第二页要求读完第三页,于是他又读了第三页。
第三天Carol读了第四页,第四页要求读完第五页,第五页又要求读完第六页,于是他把这些页都读了。
样例2解释:
第一天Carol读了第1, 3页
第二天Carol读了第2, 4页
第三天Carol读了第5, 8, 10页
第四天Carol读了第6, 7页
第五天Carol读了第9页
对于20%的数据,ai=i
对于另外20%的数据,ai = min(i + 2, n)
对于所有数据,1≤n≤100000
以 a [ i ] = i 的点为根,对于其他 a [ i ] 和 i ,直接建个 a [ i ] 到 i 的边,那么从每个根开始搜,他们的叶子结点个数之和即为最小天数。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N=100010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;
int n;
int a[N];
int e[N],ne[N],h[N],idx;
int f[N],ans;
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int f)
{
int cnt=0;
for(int i=h[u];~i;i=ne[i])
{
int j=e[i];
if(j==f) continue;
cnt++;
dfs(j,u);
}
if(cnt==0) ans++;
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
memset(h,-1,sizeof h);
vector<int>v;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]==i) v.push_back(i);
else add(a[i],i);
}
int l=v.size();
for(int i=0;i<l;i++)
dfs(v[i],-1);
printf("%d\n",ans);
return 0;
}
最后题一个一个小根堆就可解决。