反正这些东西练了还不是不会。。。
还有为什么我要抄课件题解啊喂
给一个单变量、常系数的C++式子
定义模糊的部分按任意次序计算
比如a+++++a到底先a++还是++a
给定这个变量的初值,求最大可能值
例子:
5*a++-3*++a+a++
a+++++a
贪心,按照变量前面的系数大小来贪心,系数越小越先算。
证明如下
一方面,a+++++a以任意顺序算出来的结果是一样的
另外一方面,考虑4个式子,k*++a+m*a++,k*++a+m*++a,k*a+++m*a++,k*a+++m*++a
以k*++a+m*a++为例
先算第一个再算第二个,k*(a+1)+m*(a+1)
反过来,k*(a+2)+m*a,即系数越小的越先算
证明中并没有要求a的值的正负,所以就算是负数证明也是成立的
其实感觉这个题还好,主要是实现起来有一些麻烦。
因为没有常数项,所以考虑按符号,系数,字母这样的顺序进行处理,与洛谷P1022的处理类似
代码如下(丑陋如斯)
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a,ans,cnt,len;char ch[1000005]; struct node{int k,id;}q[1000005]; bool num(int a){return ‘0‘<=a&&a<=‘9‘;} bool cmp(node a,node b){return a.k==b.k?a.id<b.id:a.k<b.k;} int main() { scanf("%d%s",&a,ch+1);len=strlen(ch+1); for(int i=1;i<=len;i++) { if(ch[i]==‘a‘) { if(i==1||ch[i-1]==‘+‘)q[++cnt]=(node){1,1}; if(ch[i-1]==‘-‘)q[++cnt]=(node){-1,1};i+=3;continue; } if(ch[i]==‘+‘) { if(i==1||ch[i-1]==‘+‘)q[++cnt]=(node){1,0}; if(ch[i-1]==‘-‘)q[++cnt]=(node){-1,0};i+=3;continue; } if(num(ch[i])) { int n=0,be=i; while(num(ch[i]))n=n*10+ch[i]-‘0‘,i++;i++; if(ch[i]==‘a‘) { if(be==1||ch[be-1]==‘+‘)q[++cnt]=(node){n,1}; if(ch[be-1]==‘-‘)q[++cnt]=(node){-n,1};i+=3;continue; } if(ch[i]==‘+‘) { if(be==1||ch[be-1]==‘+‘)q[++cnt]=(node){n,0}; if(ch[be-1]==‘-‘)q[++cnt]=(node){-n,0};i+=3;continue; } } } sort(q+1,q+1+cnt,cmp); for(int i=1;i<=cnt;i++) { if(q[i].id==1) ans+=q[i].k*(a++); else ans+=q[i].k*(++a); } printf("%d\n",ans); }
把1~n这n个数分成若干组,使得每组内的数的和是质数。任何一种分法都可以要求组数最少
n ≤ 6000
构造
用哥德巴赫猜想(小范围的正确性?),一个大于2的偶数可以被拆分成两个质数的和
1~n的和为质数,只用分一组
1~n的和为偶数,拆成两个质数
1~n的和为奇数,拆成3+两个质数或者2+质数
显然是组数最少的分法
然而一开始我忘了哥德巴赫猜想是个什么
代码
#include<cstdio>
int n,sum,col[6005];
bool pan(int a){for(int i=2;i*i<=a;i++)if(a%i==0)return 0;return 1;}
int main()
{
scanf("%d",&n);sum=n*(n+1)/2;
if(pan(sum)){for(int i=1;i<=n;i++)printf("1%c",i==n?‘\n‘:‘ ‘);return 0;}
if(sum%2)
{
if(pan(2)&&pan(sum-2))
{for(int i=1;i<=n;i++)printf("%d%c",i==2?2:1,i==n?‘\n‘:‘ ‘);return 0;}
int ans;
for(int i=2;i<=n;i++)
{
if(i==3)continue;
if(pan(i)&&pan(sum-3-i)){ans=i;break;}
}
col[3]=2;col[ans]=3;
for(int i=1;i<=n;i++)printf("%d%c",col[i]?col[i]:1,i==n?‘\n‘:‘ ‘);
}
else
{
int ans;
for(int i=2;i<=n;i++)if(pan(i)&&pan(sum-i)){ans=i;break;}
for(int i=1;i<=n;i++)printf("%d%c",i==ans?2:1,i==n?‘\n‘:‘ ‘);
}
return 0;
}
找n个不同的数a1,…,an
使得lcm(a1,…,an)=a1+…+an
只需要求一个任意可行解
n ≤ 200,ai ≤ 10^100
发现等比数列1,p,p^2,p^3......的前n-1项和为(p^n-1)/(p-1),lcm为p^(n-1) ←说得好像高中还学了什么其他数列似的
除数是p-1就很烦,所以考虑p取2
1,2,4,8,16,32......
就有和为2^n-1,lcm为2^(n-1)
和那里少了一个1,就把2变成3
1,3,4,8,16,32......
和就变为2^n = 2*2^(n-1),lcm变为3*2^(n-1),少了一个2^(n-1),但可以添加一个3的因子
再把2^(n-2)这一项乘上一个3,就可以弥补那个2^(n-1)。
这是前n-1的情况,推一下n的情况可以发现答案为
3*2^(n-1),2^n,2^(n-2),…,4,3,1
还有,这个题要写高精度。。。
代码
#include<cstdio>
#include<cstring>
int T,n,num[105],sp[105];
void mul(){for(int i=1;i<=100;i++)num[i]*=2;for(int i=1;i<=100;i++)if(num[i]>9)num[i+1]+=num[i]/10,num[i]%=10;}
void mul3(){for(int i=1;i<=100;i++)sp[i]=num[i]*3;for(int i=1;i<=100;i++)if(sp[i]>9)sp[i+1]+=sp[i]/10,sp[i]%=10;}
void print(){for(int i=100,flag=0;i>=1;i--){flag|=(num[i]>0);if(flag)printf("%d",num[i]);}puts("");}
void print1(){for(int i=100,flag=0;i>=1;i--){flag|=(sp[i]>0);if(flag)printf("%d",sp[i]);}puts("");}
int main()
{
scanf("%d",&T);
while(T--)
{
memset(num,0,sizeof num);memset(sp,0,sizeof sp);num[1]=1;
scanf("%d",&n);
if(n==2){printf("-1\n");continue;}if(n==3){printf("10\n20\n30\n");continue;}
for(int i=1;i<n;i++)
{
if(i==2){printf("3\n");mul();continue;}
if(i==n-1){mul3();mul();print();print1();continue;}
print();mul();
}
puts("");
}
}
n个小孩围成一个圈,老师顺时针隔0,1,2,…个小孩发糖,问每个小孩是否都能领到糖。
n ≤ 10^9
通过找规律可以发现,若n是2的幂,那么就可以,反之不行
证明
设f(x)=x(x-1)/2,那么相当于证明f(1),…,f(n)构成n的完全剩余系
即证明对于所有的i,j,f(i)!=f(j) (mod n)
i*(i-1)/2 != j*(j-1)/2 (mod n)
(i-j)*(i+j+1)/2 != 0 (mod n)
i-j和i+j+1的奇偶性不同,故(i-j)*(i+j+1)/2必为奇数*一个数的形式
由i,j的任意性,只有当n为2的幂的时候才成立
应该是这些题中代码量最短的代码
#include<cstdio>
long long n,a[35];
int main()
{
a[0]=1;
for(int i=1;i<=30;i++)a[i]=a[i-1]*2ll;
while(scanf("%lld",&n)!=EOF)
{
int flag=0;
for(int i=0;i<=30;i++)
flag|=(a[i]==n);
if(flag)puts("YES");
else puts("NO");
}
return 0;
}
一个n*m棋盘上每个格子摆放一个硬币,有正有反
每次选择一枚正面的硬币(x,y),从(x,y)向右下角所有的硬币都被翻转
当某个人无法翻硬币(所有硬币都是反面) ,这个人判输
1 ≤ n,m ≤ 100
每次最右下角的硬币都必被翻(谁一来就想得到啊喂)
所以若一开始右下角的硬币是正面,那么后手的人一定把这个硬币翻回正面,从而让先手的人有硬币可翻
从而这枚硬币决定了胜负。
所以,这就是细节决定成败(雾
代码
#include<cstdio>
long long T,n,m,cnt,a[105][105];
int main()
{
scanf("%lld",&T);
while(T--)
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%lld",&a[i][j]);
if(a[n][m]==1)puts("Alice");
else puts("Bob");
}
return 0;
}
1堆石子有n个,两人轮流取
先取者第1次可以取任意多个,但不能全部取完
以后每次取的石子数不能超过上次取子数的2倍
取完者胜
2 ≤ n < 2^31
找规律可知若n是斐波那契数,那么先手必败,否则必胜
证明
斐波那契数的情形,首先f[1]=2的情形先手必败,用归纳法
f[n]=f[n-1]+f[n-2]
先手不能取超过f[n-2]的石子,因为f[n-1]<2*f[n-2]
那么由归纳假设可知一定是后手取到f[n-2]这堆石子的最后一颗
但后手取完f[n-2]这堆石子的最后一颗后,先手并不能一下子取完f[n-1]这堆石子,由归纳假设可得也是后手取到f[n-1]这堆石子的最后一颗
非斐波那契数的情形,由Zeckendorf定理,任何正整数可以表示为若干个不连续的斐波那契数之和
当n不是斐波那契数时,n=f[a1]+f[a2]+…+f[ap] (p>1)
a1>a2>…>ap
由于不连续,所以先手的人可以一下子取完ap这堆石子
且后手的人不能一下子取完a(p-1)这堆石子
那么对于后手的人而言,是先手取a(p-1)这堆石子,结果是先手的人取完a(p-1)这堆石子
所以先手必胜
代码
#include<cstdio>
long long n,fib[55];
int main()
{
fib[1]=fib[2]=1;for(int i=3;i<=50;i++)fib[i]=fib[i-1]+fib[i-2];
while(scanf("%lld",&n)&&n)
{
int flag=0;
for(int i=1;i<=50;i++)flag|=(n==fib[i]);
if(flag)puts("Second win");
else puts("First win");
}
return 0;
}
n堆石子,每一次可以从任意一堆中拿走任意个石子,也可以将一堆石子分为两个小堆
先拿完者获胜
n ≤ 10^6, 石子数量在int范围内
sg函数和sg定理
sg(0)=0,sg(1)=mex(sg(0))=1,sg(2)=mex(sg(0),sg(1),sg(1)^sg(1))=2
递推对于此题的大范围是不可行的
通过sg函数找规律,来做大范围的情况
代码
#include<cstdio>
int T,i,n,x,ans;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(ans=0,i=1;i<=n;i++)
{
scanf("%d",&x);
if(x%4==3)ans^=x+1;
if(x%4==0)ans^=x-1;
if(x%4==1||x%4==2)ans^=x;
}
if(ans)puts("Alice");
else puts("Bob");
}
return 0;
}
有一枚棋子,从(1,1)到(n,m),两人轮流走,先到的赢
棋子是以下四种类型之一:
王:只能右、下和斜着走一格。
皇后:和王一样,但是可以任意步。
骑士:只能右、下,但是可以任意步。
马:走日(右下方)。
2 ≤ n,m ≤ 1000
王的情形
用sg函数打表找规律
sg(1,1)=0
sg(x,y)=mex(sg(x-1,y),sg(x,y-1),sg(x-1,y-1))
后的情形
相当于两堆物品分别有n,m个,每次从任一堆取至少一个或同时从两堆中取同样多个,最后取光者胜
wythoff博弈
骑士的情形
相当于两堆物品分别有n,m个,每次从任一堆取至少一个,最后取光者胜
nim博弈
马的情形
题目要求不能移动且没有到右下角时为平手
对于当前位置,如果能走到必败态,那么一定是必胜态
若不能走到必败态,那么如果能走到平局位置,则一定是平局
然后。。。。打表大法好
代码
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
int T,type,n,m;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&type,&n,&m);
if(type==1){if(n%2==1&&m%2==1)puts("G");else puts("B");}
if(type==2){if(n^m)puts("B");else puts("G");}
if(type==3)
{
if((n+m)%3!=2)puts("D");
else if(m==n)puts("G");
else if(abs(n-m)==1)puts("B");
else puts("D");
}
if(type==4)
{
n--,m--;
if(n>m)swap(n,m);int k=m-n;
if(int(double(k)*((1.0+sqrt(5.0))/2.0))==n&&int(double(k)*((3.0+sqrt(5.0))/2.0))==m)
puts("G");else puts("B");
}
}
return 0;
}
原文:https://www.cnblogs.com/firecrazy/p/11435146.html