三道思维题,分享一下
第一题
melon
【时间限制】1000MS 【空间限制】65536KB
【输入文件】melon. in 【输出文件】melon.out
【题目描述】
Todobe和Yahsem66比赛吃瓜。
桌上一共有n块瓜,他们可以从桌上拿走不多于k块瓜来吃,吃一块瓜需要1分钟的时间,只有吃完手里的所有瓜之后才可以再去拿瓜,拿瓜的时间不计。如果两人在同一时间点拿瓜,Yashem66会发扬谦让精神让Todobe先拿,开始比赛时也是Todobe先拿。
举个例子,如果n=10,k=4,Todobe先拿走3块,Yashem66拿走2块,Yashem66吃完之后Todobe还有1块没有吃完。Yashem66再拿走4块,然后Todobe就只能再吃到1块,最终Todobe吃了4块,而Yashem66吃了6块。
两个人都想尽可能吃更多的瓜,贪吃的Todobe想知道她最多能吃到多少块瓜。
【输入】
输入包括一行两个整数,n、k。
【输出】
输出一行一个整数,代表Todobe最多能吃到多少块瓜。
【样例输入1】
2 1
【样例输出1】
1
【样例输入2】
10 4
【样例输出2】
5
【数据范围与约定】
对于0%的数据,与样例相同;
对于10%的数据,n<=2*k;
对于另30%的数据,k=2;
对于100%的数据,n,k<=100000。
这道题就是考虑情况周全,n<=k直接是n,k<n<=2k就是k
当n>2k时,考虑一次只吃一个瓜,这样就有更大决策空间
当剩余瓜数<=2*k时直接选k个
所以答案为ceil(n/2)
Code
#include<cstdio>
#include<iostream>
using namespace std;
int n,k;
int main()
{
freopen("melon.in","r",stdin);
freopen("melon.out","w",stdout);
scanf("%d%d",&n,&k);
if(n<=k)
{
printf("%d",n);
}
else if(n<=2*k)
{
printf("%d",k);
}
else printf("%d",(n+1)/2);
return 0;
}
第二题
change
【时间限制】2000MS 【空间限制】524288KB
【输入文件】change.in 【输出文件】change.out
【题目描述】
Todobe开了一家店,Yashem66连续n天都会光顾这家店。
Yashem66只有100元的纸币和1元的硬币,他知道Todobe懒的一批,很讨厌找零这件事情,每天Todobe都会有一个心情值wi,如果Todobe第i天需要找零,那她的不愉悦度就会增加wi*找零的钱数。当Todobe需要找零时,她也会找给Yashem66若干1元硬币,但她不会找给Yashem66 100个及以上的硬币。
假设Yashem66一开始有足够的纸币和m个硬币,他在第i天,会买价值ci元的产品。他想尽可能降低Todobe的不愉悦度,请你告诉他Todobe 的不愉悦度最少是多少。
【输入】
第一行两个整数n、m。
第二行有n个整数,第i个整数代表ci,第i天Yashem66购买的价格。
第三行有n个整数,第i个整数代表wi,第i天Todobe的心情值。
【输出】
输出一行一个整数代表Todobe不愉悦度的最小值。
【样例输入1】
5 42
117 71 150 243 200
1 1 1 1 1
【样例输出1】
79
【样例解释1】
第一天花费1张100元纸币和17个1元硬币,剩余25个硬币,不愉悦度为0;
第二天花费1张100元纸币,找零29,剩余54个硬币,不愉悦度为29;
第三天花费2张100元纸币,找零50,剩余104个硬币,不愉悦度为79;
第四天花费2张100元纸币和43个1元硬币,剩余61个硬币,不愉悦度为79;
第五天花费2张100元纸币,不愉悦度为79.
【样例输入2】
5 42
117 71 150 243 200
5 4 3 2 1
【样例输出2】
230
【样例解释2】
第一天花费1张100元纸币和17个1元硬币,剩余25个硬币,不愉悦度为0;
第二天花费1张100元纸币,找零29,剩余54个硬币,不愉悦度为116;
第三天花费1张100元纸币和50个1元硬币,剩余4个硬币,不愉悦度为116;
第四天花费3张100元纸币,找零57,剩余61个硬币,不愉悦度为230;
第五天花费2张100元纸币,不愉悦度为230.
【数据范围与约定】
对于0%的数据与样例相同;
对于20%的数据,n<=20;
对于另20%的数据,ci=1;
对于100%的数据,n<=105,m<=109,1<=ai,ci<=10^5。
首先一个优化,就是0<=c[i]<100,先%100
这道题考虑贪心,就是只要能买就买,如果钱不够了怎么办?
考虑之前买的,因为已经付了c[i],而找零是100-c[i],加一起就是你花100-c[i]的不愉悦度,得到100元,用堆维护每次取最小即可
Code
#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
struct poi
{
int id,num;
bool operator < (const poi &a)const
{
return num>a.num;
}
};
int n,m;
int c[100005];
int w[100005];
long long ans;
priority_queue<poi> q;
int ans2[100005];
int minn=1000000000;
int anss[100005];
void dfs(int x,int lst,int un)
{
if(lst<=anss[x]&&un>=ans2[x])return ;
if(lst>=anss[x]&&un<=ans2[x])
{
anss[x]=lst;
ans2[x]=un;
}
if(x==n)
{
minn=min(minn,un);
return ;
}
if(lst>=c[x+1])dfs(x+1,lst-c[x+1],un);
dfs(x+1,lst+100-c[x+1],un+w[x+1]*(100-c[x+1]));
}
int main()
{
freopen("change.in","r",stdin);
freopen("change.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&c[i]);
c[i]%=100;
}
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
}
if(n<=20)
{
dfs(0,m,0);
printf("%d",minn);
return 0;
}
for(int i=1;i<=n;i++)
{
if(!(c[i]%100))continue;
poi x;
x.id=i;
x.num=w[i]*(100-c[i]);
q.push(x);
m-=c[i];
if(m<0)
{
poi cc=q.top();
q.pop();
ans+=cc.num;
m+=100;
}
}
printf("%lld",ans);
}
第三题
:我出这道题就不是让你们做的。。。
好吧,我连矩乘都不会
paint
【时间限制】1000MS 【空间限制】524288KB
【输入文件】paint.in 【输出文件】paint.out
【题目描述】
Todobe要把她的寝室弄得漂漂酿酿,所以她管Yashem66要了一些墙纸。
Todobe有一面墙,可分为n块,Yashem66提供的所有墙纸都是统一规格的,均只可覆盖连续k块完整的墙面,但是有m种不同的颜色的墙纸,每种颜色的墙纸都有无限张。Todobe要用这些墙纸把墙贴满,墙纸不可以裁剪,墙纸与墙纸之间可以有重叠部分。当墙纸重叠时,只能看到最外层的墙纸颜色。
Todobe想知道她以不同的方式贴墙纸,共能贴出多少种不同配色方案的墙面,两种方案不同当且仅当两种方案中至少有一块墙面的颜色不同。
【输入】
输入一行3个整数n,m,k。
【输出】
输出一行一个整数代表方案数量,答案取模1e9+7。
【样例输入1】
3 2 2
【样例输出1】
6
【样例输入2】
10 4 3
【样例输出2】
371740
【样例解释】
对于样例输入1,我们假设两种颜色分别是A,B
那么6种方案分别是:AAA,AAB,ABB,BAA,BBA,BBB
【数据范围与约定】
对于0%的数据,与样例数据相同;
对于20%的数据,n<=10,m<=5;
对于另20%的数据n<=500;
对于另20%的数据n<=10^5;
对于100%的数据n<=231-1,m<=10^5,k<=100。
这道题可以先求出不合法方案数,再用nm减一下就好了
原题变成求m种颜色若干段区间,每段都小于k
f[i]=(f[i-1]+f[i-2]+……+f[i-k+1])*(m-1)
矩乘优化就好了
不会戳这里
Code
#include<bits/stdc++.h>
using namespace std;
int n,m,K;
const int mod=1000000007;
struct mat
{
long long a[105][105];
mat operator *(const mat &x)const
{
mat f;
for(int i=0;i<K;i++)
for(int j=0;j<K;j++)
{
f.a[i][j]=0ll;
for(int k=0;k<K;k++)
f.a[i][j]=(f.a[i][j]+a[i][k]*x.a[k][j])%mod;
}
return f;
}
}A,T;
long long ksm(int x,int y)
{
long long re=1;
long long pl=x;
while(y)
{
if(y&1)re=re*pl%mod;
pl=pl*pl%mod;
y>>=1;
}
return re;
}
void ksm(mat x,int y)
{
while(y)
{
if(y&1)
{
A=A*x;
}
x=x*x;
y>>=1;
}
return ;
}
long long ans;
int main()
{
freopen("paint.in","r",stdin);
freopen("paint.out","w",stdout);
scanf("%d%d%d",&n,&m,&K);
ans=ksm(m,n);
K--;
A.a[0][0]=m;
for(int i=1;i<K;i++)
A.a[0][i]=A.a[0][i-1]*m%mod;
for(int i=0;i<K-1;i++)
{
T.a[i+1][i]=1;
}
for(int i=0;i<K;i++)
T.a[i][K-1]=m-1;
ksm(T,n-K);
ans=((ans-A.a[0][K-1])%mod+mod)%mod;
printf("%lld",ans);
return 0;
}