A 托米的赌球【贪心】
模拟,从最大的钱数直接贪心来。
#include
using namespace std;
#define ll long long int
ll a[15]={10000,5000,2000,1000,500,200,100,50,20,10,5,2,1};
ll vis[15];
int main()
{
int T;
scanf("%d",&T);
while(T--){
ll x,y;
scanf("%lld %lld",&x,&y);
x=x*100+y;
memset(vis,0,sizeof vis);
for(int i=0;i<13;i++){
while(x-a[i]>=0){
vis[i]++;
x-=a[i];
}
}
for(int i=0;i<13;i++){
if(i) printf(" ");
printf("%lld",vis[i]);
}
printf("\n");
}
return 0;
}
B 托米的划分【记忆化||贪心】
每次划1是最优的,直接记忆化也OK。
#include
using namespace std;
#define ll long long int
ll a[15]={10000,5000,2000,1000,500,200,100,50,20,10,5,2,1};
ll vis[15];
int main()
{
ll ans=0;
int T;
scanf("%d",&T);
while(T--){
ll n;
scanf("%lld",&n);
ans=(n*(n-1))/2;
printf("%lld\n",ans);
}
return 0;
}
C 托米的位运算【枚举lowbit】
来看一下,某一位能否被构造出来,按照题目要求取最优解。
#include
using namespace std;
#define ll long long int
#define lowbit(x) (x&(-x))
const int maxn=1e5+2333;
int a[maxn];
int vis[maxn];
int p[35];
int n;
int main()
{
scanf("%d",&n);
p[0]=p[1]=1;
for(int i=2; i<=31; i++) p[i]=p[i-1]*2;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
int ans=0;
int cs=0;
int x;
int tmp=0;
int cz=0;
for(int i=31; i>=1; i--)
{
tmp=0;
cz=0;int flag=0;
for(int j=1; j<=n; j++)
{
if(a[j]&p[i])
{
if(!flag) tmp=a[j],flag=1;
else tmp=tmp&a[j];
cz++;
// cout<<1<
}
}
//cout<
if(lowbit(tmp)==p[i])
{
tmp=0;
cz=0;
cs=0;flag=0;
for(int j=1; j<=n; j++)
{
if(a[j]&p[i])
{
vis[++cs]=j;
if(!flag) tmp=a[j],flag=1;
else tmp=tmp&a[j];
}
}
break;
}
}
printf("%d\n",cs);
for(int i=1;i<=cs;i++){
if(i^1) printf(" ");
printf("%d",a[vis[i]]);
}
return 0;
}
D 托米的咒语【全排列+二分】
把每一种字母出现的所有位置都记录下来,然后枚举全排列,根据每一种情况,二分查找下一个放的字母的位置,如果所有字母全都能找到的话ans++。
#include
using namespace std;
const int maxn=3e3+25;
char s[maxn];
int a[maxn];
int cnt[12][maxn];
int vis[12];
int x[10];
int main()
{
memset(vis,0,sizeof vis);
scanf("%s",s);
int len=strlen(s);
for(int i=0;i1]=(s[i]-'a')+1;
}
for(int i=1;i<=len;i++){
cnt[a[i]][++vis[a[i]]]=i;
}
for(int i=0;i<9;i++) x[i]=i+1;
int ans=0;
do{
int tmp=0;bool flag=1;
for(int i=0;i<9;i++){
tmp=upper_bound(cnt[x[i]]+1,cnt[x[i]]+1+vis[x[i]],tmp)-cnt[x[i]];
if(tmp>vis[x[i]]) {flag=0;break;}
tmp=cnt[x[i]][tmp];
}
if(flag) ans++;
//cout<
}while(next_permutation(x,x+9));
printf("%d\n",ans);
return 0;
}
E 托米的数学【欧拉函数||费马小定理】
题目中给出的数字是“走马灯数”,是非常有趣的一种数字。
有关知识和这个题的结论参考自:
https://zhuanlan.zhihu.com/p/27853213
#include
using namespace std;
#define ll long long int
#define INF 0x3f3f3f3f
#define clr(x,y) memset(x,y,sizeof x);
const int maxn=2e4+23;
bool ispri(ll x){
for(ll i=2;i*i<=x;i++){
if(x%i==0) return 0;
}
return 1;
}
ll qkm(ll a,ll b,ll p){
ll ans=1;
while(b>0){
if(b%2){
ans=ans*a;ans%=p;
}
a=a*a;a%=p;b>>=1;
}
return ans;
}
ll judge(ll x,ll p){
for(ll i=2;i*i<=p-1;i++){
if((p-1)%i==0){
if(qkm(x,i,p)==1||qkm(x,(p-1)/i,p)==1){
return 0;
}
}
}
return 1;
}
ll n,x;
int main()
{
cin>>n>>x;
if(ispri(n+1)){
for(ll i=x-1;i>=2;i--){
if(judge(i,n+1)){
printf("%d\n",i);
return 0;
}
}
}
puts("-1");
return 0;
}
F 托米的游戏【树形DP期望】
期望和树的层数有关,也和每一层的节点个数有关。经过测试和推导发现,答案是所有节点深度之和的一半,在取模意义下通过费马小定理解决除法问题。
#include
using namespace std;
#define ll long long int
#define lowbit(x) (x&(-x))
const int maxn=1e5+2333;
int a[maxn];
int vis[maxn];
int p[35];
int n;
int main()
{
scanf("%d",&n);
p[0]=p[1]=1;
for(int i=2; i<=31; i++) p[i]=p[i-1]*2;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
int ans=0;
int cs=0;
int x;
int tmp=0;
int cz=0;
for(int i=31; i>=1; i--)
{
tmp=0;
cz=0;int flag=0;
for(int j=1; j<=n; j++)
{
if(a[j]&p[i])
{
if(!flag) tmp=a[j],flag=1;
else tmp=tmp&a[j];
cz++;
// cout<<1<
}
}
//cout<
if(lowbit(tmp)==p[i])
{
tmp=0;
cz=0;
cs=0;flag=0;
for(int j=1; j<=n; j++)
{
if(a[j]&p[i])
{
vis[++cs]=j;
if(!flag) tmp=a[j],flag=1;
else tmp=tmp&a[j];
}
}
break;
}
}
printf("%d\n",cs);
for(int i=1;i<=cs;i++){
if(i^1) printf(" ");
printf("%d",a[vis[i]]);
}
return 0;
}