A - The Super Powers
UVA - 11752
题解:每个符合的结果的幂都不是素数 所以枚举每个数的非素数幂,注意ull 它输出格式为%lu
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<string.h>
#include<set>
#include<algorithm>
#define maxn 100
using namespace std;
bool isPrime[maxn];
void getPrime()
{
memset(isPrime,true,sizeof(isPrime));
isPrime[0]=isPrime[1]=false;
for(int i=2;i<maxn;i++)
if(isPrime[i])
{
for(int j=i+i;j<maxn;j+=i)
isPrime[j] = false;
}
}
set<unsigned long long> s;
int main()
{
getPrime();
s.clear();
s.insert(1);
for(int i = 2; i < 65536; i ++ )//2^16
{
double m=(64.0 * log(2))/log(i)-1;// ln(x^k)<ln(2^64)-1;//
unsigned long long tmp = i;
for(int j=2; j <= ceil(m); j++)
{
tmp *= i;
if(isPrime[j]) continue;
s.insert(tmp);
}
}
set<unsigned long long> :: iterator it;
for(it=s.begin();it != s.end(); it ++)
printf("%lu\n",*it);//
return 0;
}
B - Maximum GCD
UVA - 11827
//求n个数的最大公约数,处理下输入
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
#define ll long long
const int maxn=10000010;
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
char s[maxn];
int a[220];
int main()
{
int n;
scanf("%d",&n);getchar();
while(n--){
gets(s);
int len=strlen(s);
int u=0;
for(int i=0;i<len;i++){
int sum=0;
while(i<len&&s[i]!=' '){
sum=sum*10+s[i]-'0';
i++;
}
a[u++]=sum;
}
int ans=0;
for(int i=0;i<u;i++)
for(int j=i+1;j<u;j++)
ans=max(ans,gcd(a[i],a[j]));
printf("%d\n",ans);
}
return 0;
}
C - Paint Chain
HDU - 3980
题解转载自:https://blog.csdn.net/zhjchengfeng5/article/details/8214768
题意
两个人在一个由 n 个玻璃珠组成的一个圆环上玩涂色游戏,游戏的规则是:
1、每人一轮,每轮选择一个长度为 m 的连续的、没有涂过色的玻璃珠串涂色
2、不能涂色的那个人输掉游戏
可以肯定的是,第一个人涂色之后就把环变成了一个长度为 n-m 的链了,那么我们就可以这样划分阶段了:每轮从一些线段中选择一个,并且把那条线段分成 x, m, len-x-m 的三个部分,其中 len 表示线段原来的长度,m 表示的是已经涂色了,那么这个长为 len 的线段能够得到的子状态最多有 len-m+1 个(其实由对称性可知实际的状态数只是这里的一半),变成了两个长度为 x 和 len-x-m 子游戏,由 SG 定理,SG(len)=SG(x)^SG(len-x-m) 而再由 SG 函数的定义式 SG[u]=mex(seg[v]) 其中,状态 u 可以直接得到状态 v,再加上一个记忆化的小优化,AC了
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
using namespace std;
int t, n, m;
int f[1005];
bool emerge[1000];
int get_sg(int len)
{
if(len<m) return f[len]=0;
if(f[len]!=-1) return f[len];
bool vs[1001]={0};
for(int i=0; len-i-m>=0; i++)
vs[get_sg(i)^get_sg(len-i-m)]=1;
for(int i=0; i<1001; i++)
if(!vs[i]) return f[len]=i;
}
int main()
{
scanf("%d", &t);
for(int ca=1; ca<=t; ca++)
{
scanf("%d%d", &n, &m);
memset(f, -1, sizeof(f));
printf("Case #%d: ", ca);
if(n<m || get_sg(n-m)) printf("abcdxyzk\n");
else printf("aekdycoin\n");
}
return 0;
}
D - Fliping game
HDU - 4642
题解转载自:https://blog.csdn.net/scnu_jiechao/article/details/9706963
题意:Alice和Bob玩游戏,一个N * M的矩阵,里面是1或0,每人每次选择一个1的位置,然后将这个位置到右下角的整个矩形元素全部取反(1变0,0变1),最后不反操作(没有1)的人输,Alice先行(1 <= N, M <= 100),输出胜者。
因为胜者最后一步一定是将所有的格子变成0,假设最后一个元素是1,每一次翻转,Alice都会将最后一个元素变成0,而Bob每一次都会将最后一个元素变成1,最后也就会是Alice胜;假设最后一个元素是0,每一次翻转,Alice都会将最后一个元素变成1,而Bob每一次都会将最后一个元素变成0,最后也就会是Bob胜。
所以,Alice的输赢取决于最后一个元素,是1就赢,是0就输
#include <cstdio>
using namespace std;
int main()
{
int T, N, M, a, i, j;
scanf("%d", &T);
while(T--){
scanf("%d%d", &N, &M);
for(i = 0; i < N; i++)
for(j = 0; j < M; j++)
scanf("%d", &a);
if(a == 1) printf("Alice\n");
else printf("Bob\n");
}
return 0;
}
E - A Dangerous Maze
LightOJ - 1027
题解转载自:https://blog.csdn.net/yeyeyeguoguo/article/details/46417489
题意:
你在一个迷宫里,面前有n扇们,每个门有一个数字k;
如果k为正数,则通过这扇门,走k分钟就能出去,如果为负数,则通过这扇门走-k的分钟回到迷宫;
走每扇门概率一样.问走出迷宫所需时间的期望值;
思路:首先如果全是负数肯定是inf;然后我们假设我们走出去的期望时间是d;
那么拿第三个样例举例子; d = 1/3 * 3 + 1/3( 6 + d) + 1/3 (9 + d);
意思就是每扇门被选择的概率是1/3;选选第一扇门要花3分钟出去,选第二扇门要6 + d(花6分钟返回原地,在花期望d出去);然后根据这个式子求出d;并用分数表示;
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct frac{
int u;
int d;
}f;
frac add(frac a, frac b){
if(a.d == 0)
return b;
frac tmp;
int up = a.u * b.d + a.d * b.u;
int down = a.d * b.d;
int c = __gcd(up, down);//系统自带的 gcd
tmp.u = up / c;
tmp.d = down / c;
return tmp;
}
int main() {
int t, n;
int cas = 1;
scanf("%d",&t);
while(t--) {
scanf("%d",&n);
int d = 0;
frac num;
num.u = 0;
num.d = 0;
int tmp;
for(int i = 0; i < n; i++) {
scanf("%d",&tmp);
if(tmp > 0) {
f.u = tmp;
f.d = n;
num = add(num, f);
}else {
f.u = -tmp;
f.d = n;
num = add(num, f);
d++;
}
}
if(d == n) {
printf("Case %d: inf\n",cas++);
continue;
}
num.u *= n;
num.d *= (n - d);
int c = __gcd(num.u, num.d);
printf("Case %d: %d/%d\n",cas++, num.u / c, num.d / c);
}
return 0;
}
F - Birthday Paradox
LightOJ - 1104
题解转载自:https://blog.csdn.net/hyczms/article/details/46460401
题意:假设一年有n天,问至少有多少个人,能保证至少其中两个人的生日在同一天的概率大于等于0.5。
题解:要计算至少两个人的生日同天概率可以逆着算所有人不同天生日的概率小于0.5,那么人数就是x = 1 * (n - 1)/n * (n-2)/n * … 直到x是小于0.5的
#include <stdio.h>
#include <string.h>
#include <math.h>
int n;
int main() {
int t, cas = 1;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
int cnt = 0;
double temp = 1;
while (temp > 0.5) {
cnt++;
temp *= (n - cnt) * 1.0 / n;
}
printf("Case %d: %d\n", cas++, cnt);
}
return 0;
}
G - Dice (III)
LightOJ - 1248
题解转载自:https://blog.csdn.net/chy20142109/article/details/51774631
题意:有一个n面的骰子,每次投掷每个面都是等概率出现,求所有面都出现的期望投掷次数。思路:f[i]表示已经出现了i个面,还需要投掷的期望次数,f[n] = 0 , f[i] = i/n * f[i] + ( n - i ) / n * f[i+1] + 1 ,
化简后f[i] = f[i+1] + n / ( n - i ) , 所以答案就是∑n/i 1<=i<=n。
#include<cstdio>
#include<cmath>
using namespace std;
int main()
{
int T,n,t=1;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
double ans=0.0;
for(int i=1;i<=n;i++)
ans+=1.0*n/i;
printf("Case %d: %f\n",t++,ans);
}
return 0;
}
H - Finite or not?
CodeForces - 984C
题解转载自:
题意:输入p q b问p/q在 b进制中是否为有限小数
题解:先gcd去除p的贡献,然后对于1/q是否能被b表示,则看1/q=1/b+1/b^2+…+能否被表示,对1/q每次都乘以b,再约分,(这个过程相当于q和无穷多个b进行疯狂约分),如果最后1/q能化为1,则说明1/q在b进制为有限小数。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
#define ll long long
const int maxn=300010;
ll p,q,b;
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
//int gcd(int a,int b)
//{
// return b?gcd(b,a%b):a;
//}
bool ok()
{
ll m=gcd(p,q);
q/=m;
m=b;
while(q!=1){
m=gcd(q,m);
q/=m;
if(m==1) break;
}
if(q==1)
return true;
return false;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%I64d%I64d%I64d",&p,&q,&b);
if(!p||ok())
printf("Finite\n");
else
printf("Infinite\n");
}
return 0;
}
I - Modular Equations
CodeForces - 495B
题意:满足
a
%
x
=
=
b
a\%x==b
a%x==b的所有x,输入a b输出满足的x的个数,有无穷个输出无穷
题解:a%x==b <=> (a-b)%x==0
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
#define ll long long
const int maxn=10000010;
set<int> st;
int get(int x,int b)
{
st.clear();
int ans=0,m=sqrt(x);
for(int i=1;i<=m;i++){
if(x%i==0){
int j=x/i;
if(i>b&&st.find(i)==st.end()){
ans++;
st.insert(i);
//printf("i:%d\n",i);
}
if(j>b&&st.find(j)==st.end()){
//printf("j:%d\n",j);
st.insert(j);
ans++;
}
}
}
//if(x%m==0) ans--;
return ans;
}
int main()
{
int a,b;
while(~scanf("%d%d",&a,&b)){
if(a==b){
printf("infinity\n");
continue;
}
if(b>a){
printf("0\n");
continue;
}
printf("%d\n",get(a-b,b));
}
return 0;
}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
#define ll long long
const int maxn=10000010;
set<int> st;
int get(int x,int b)
{
st.clear();
int ans=0,m=sqrt(x);
for(int i=1;i<=m;i++){
if(x%i==0){
int j=x/i;
if(i>b&&st.find(i)==st.end()){
ans++;
st.insert(i);
//printf("i:%d\n",i);
}
if(j>b&&st.find(j)==st.end()){
//printf("j:%d\n",j);
st.insert(j);
ans++;
}
}
}
//if(x%m==0) ans--;
return ans;
}
int main()
{
int a,b;
while(~scanf("%d%d",&a,&b)){
if(a==b){
printf("infinity\n");
continue;
}
if(b>a){
printf("0\n");
continue;
}
printf("%d\n",get(a-b,b));
}
return 0;
}
J - Concatenated Multiples
CodeForces - 1029D
题解转载自:http://crazyforsaken.com/?p=742
题意 对于两个数字a和b来说,如果把他们连起来取模k为0就是答案的一个贡献,现在给你n个数问有多少对(xy和yx是两种不同的)对答案有贡献?思路 对于x和y来说,如果x在前面的话,需要考虑y的位数p,对于题意显然有
(
x
∗
1
0
p
+
y
)
%
k
=
=
0
(x*10^p+y)\%k==0
(x∗10p+y)%k==0。作出相应的变形就是
(
x
∗
1
0
p
)
%
k
=
=
(
k
−
y
%
k
)
%
k
(x*10^p)\%k==(k-y\%k)\%k
(x∗10p)%k==(k−y%k)%k那么我们对于所有的输入的t,都可以处理一下把它当作前面那个数字,用mp[i][x]表示后面的数为i位时,x=t*10^i%k有这样的答案出现过,然后再遍历所有的数字当成后面的数,根据其位数去找mp[l][(k-y%k)%k]是否有对应的数存在,最后去重即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long long
const int maxn=200010;
int n,k;
int a[maxn];
map<int,ll> mp[15];
int getlen(int x)
{
int ans=0;
while(x){
x/=10;
ans++;
}
if(!ans) ans++;
return ans;
}
int main()
{
while(~scanf("%d%d",&n,&k)){
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
//memset(mp,0,sizeof(mp));
for(int i=0;i<15;i++)
mp[i].clear();
for(int i=1;i<=n;i++){
ll p=1LL;
for(int j=1;j<=10;j++){
p=p*10LL%k;
mp[j][a[i]%k*p%k]++;
}
}
ll ans=0;
for(int i=1;i<=n;i++){
ll p=1LL;
int l=getlen(a[i]);
//printf("%d: len:%d\n",i,l);
for(int j=1;j<=l;j++){
p=p*10LL%k;
}
ans+=1LL*mp[l][(k-a[i]%k)%k];
if((k-a[i]%k)%k==a[i]%k*p%k)
ans--;
}
printf("%lld\n",ans);
}
}
K - Diagonal Walking v.2
CodeForces - 1036B
题意:给一个点(n,m) 走k步,问从(0,0)出发走k步到达(n,m)时,能最多走多少对角线,如果走不到输出-1
题意:从出发点到终点,先取x,y中最大的m最小的mn,先走到同一线上,在贪心的上下走,对剩下到达终点后的步数,也贪心的上下走,注意分奇数、偶数的情况,终点和出发点一样的情况。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
#define ll long long
const int maxn=10000010;
int n;
int main()
{
int t;
scanf("%d",&t);
while(t--){
ll x,y,k;
scanf("%lld%lld%lld",&x,&y,&k);
ll mn=min(x,y),mx=max(x,y);
if(mx>k){
printf("-1\n");
continue;
}
ll ans=(mx-mn)/2*2+mn;
if((k-mx)%2){
k--;
if((mx-mn)%2){
ans++;//printf("SD\n");
}else if(ans){
ans--;
}else{
printf("-1\n");
continue;//
}
}
ans+=k-mx;
printf("%lld\n",ans);
}
return 0;
}
/*
99
2 3 3
*/
L - Vasya and Arrays
CodeForces - 1036D
题意:有两个长度为n和m的序列A和B,每次操作可以将序列连续的几个数合并为1个,该数的值是那连续几个数的和。现在进行若干次操作让A和B相等,问操作形成的相等序列的最大长度是多少。
题解:从左向右扫,并记录A和B序列的和sum1、sum2,每当和相等时,结果+1,sum1与sum2清0
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<set>
using namespace std;
#define ll long long
const int maxn=300010;
int a[maxn],b[maxn];
int n,m;
int main()
{
while(~scanf("%d",&n)){
ll cur1=0,cur2=0;//
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
cur1+=1LL*a[i];
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d",&b[i]);
cur2+=1LL*b[i];
}
if(cur1!=cur2){
printf("-1\n");
continue;
}
int i=1,j=1;
cur1=a[1],cur2=b[1];
int len=0;
while(i<=n&&j<=m){
if(cur1==cur2){
if(cur1){
cur1=cur2=0;
len++;
}else{
cur1+=1LL*a[++i];
cur2+=1LL*b[++j];
}
}
else if(cur1<cur2){
cur1+=1LL*a[++i];
}
else{
cur2+=1LL*b[++j];
}
}
printf("%d\n",len);
}
return 0;
}
M - Vasya’s Function
CodeForces - 837E
题解转载自:https://blog.csdn.net/calabash_boy/article/details/76652792
题意:定义F(a,0) = 0,F(a,b) = 1 + F(a,b - GCD(a,b)。给定 x 和 y (<=1e12)求F(x,y)。 题解:a=AGCD(a,b) b=BGCD(a,b),那么b-GCD(a,b) = (B-1)GCD(a,b),如果此时A和B-1依然互质,那么GCD不变下一次还是要执行b-GCD(a,b)。那么GCD什么时候才会变化呢?就是说找到一个最小的S,使得(B-S)%T=0其中T是a的任意一个因子。变形得到:B%T=S于是我们知道S=min(B%T)。也就是说b剪掉了S次相同的一个GCD之后,ab有了新的GCD。新的GCD等于原来的GCDT,可以把a、b都/T,同时GCD*T,这样问题化归为上述同样的问题,进行迭代。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
LL x, y;
cin >> x >> y;
LL g = __gcd(x, y);
x /= g, y /= g;
vector<LL> a;
for (LL i = 2; i * i <= x; ++ i) {
while (x % i == 0) {
x /= i;
a.push_back(i);
}
}
if (x > 1) a.push_back(x);
LL ans = 0;
while (y) {
LL g = y;
for (LL i : a) {
g = min(g, y % i);
}
ans += g;
y -= g;
vector<LL> b;
for (LL i : a) {
if (y % i == 0) {
y /= i;
}
else {
b.push_back(i);
}
}
a.swap(b);
}
cout << ans << endl;
}