http://acm.zknu.edu.cn/contest.php?cid=1118
把答案分为以零结尾的数字和不以零结尾的数字两种,开一个记录答案的数组ans[i][0/1],表示i位数以0或不以0结尾的方案数。
显然ans[1][0]=1,ans[1][1]=9。
如果以0结尾,该i位数字串的下一位可以是任何数字。如果以1结尾,该i位数字串的下一位可以是除了0以外的任何数字。
易知ans[i][0]=ans[i-1][1],ans[i][1]=(ans[i][0]+ans[i][1])*9。
求解过程中要对1e9+7取余以防溢出。
#include
const int p=1e9+7;
int n,T,a[10000001],ans[1000001][2];
int main()
{
while (scanf("%d",&a[++T])!=EOF)
if (a[T]>n) n=a[T];
T--;
ans[1][0]=1;
ans[1][1]=9;
for (int i=2;i<=n;++i)
{
ans[i][0]=ans[i-1][1];
ans[i][1]=(ans[i-1][0]*9ll%p+ans[i-1][1]*9ll%p)%p;
} //9ll是longlong类型的九,相当于进行了一次强制类型转化。
for (int i=1;i<=T;++i) printf("%d\n",(ans[a[i]][0]+ans[a[i]][1])%p);
return 0;
}
N个弹珠完全相同,且默认发生完全弹性碰撞,碰撞后两弹珠的速度和方向均交换。我们并不对弹珠们的标号与末位置的对应关系加以要求,所以可以视为弹珠之间不会发生碰撞。
计算所有弹珠的末状态,按要求排序后输出。
#include
#include
using namespace std;
struct asdf{
int x,y,z;
}a[101];
bool operator < (asdf a,asdf b)
{
if (a.x==b.x)
if (a.y==b.y) return a.z<b.z;
else return a.y<b.y;
return a.x<b.x;
}
int main()
{
int n,t,vx,vy,vz;
scanf("%d%d",&n,&t);
for (int i=1;i<=n;++i)
{
scanf("%d%d%d%d%d%d",&a[i].x,&a[i].y,&a[i].z,&vx,&vy,&vz);
a[i].x+=vx*t;
a[i].y+=vy*t;
a[i].z+=vz*t;
}
sort(a+1,a+1+n);
for (int i=1;i<=n;++i) printf("%d %d %d\n",a[i].x,a[i].y,a[i].z);
}
每一列对答案的贡献为min(它左边最大数,它右边最大数)-它自己的高度。
比如下图第三列的答案,为min(3,2)-1=2-1=1。
求出每一列的答案我们就可以累加求出总的答案。
另外开两个数组,正着遍历即可求出每个元素前面最大的元素, l[i]=max(a[i-1],l[i-1]),同理我们逆序遍历即可求出每个元素后面最大的元素r[i]=max(a[i+1],r[i+1]),最后统计答案。
我的代码中的l和r数组包含了自己,显然可以发现对最后的答案并没有影响。
#include
#include
#define min(a,b) (a>b?b:a)
int n,a[1005],l[1005],r[1005];
int qwq()
{
memset(l,0,sizeof(l));
memset(r,0,sizeof(r));
memset(a,0,sizeof(a));
int ans=0;
scanf("%d",&n);
for (int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
if (a[i]>l[i-1]) l[i]=a[i];
else l[i]=l[i-1];
}
for (int i=n;i>=1;--i)
{
if (a[i]>r[i+1]) r[i]=a[i];
else r[i]=r[i+1];
if (min(l[i],r[i])-a[i]>0) ans+=min(l[i],r[i])-a[i];
}
return ans;
}
int main()
{
int T;
for (scanf("%d",&T);T--;) printf("%d\n",qwq());
return 0;
}
题目背景中说道:冰茶几无法正确解决任何一个问题。
所以对于每组数据输出0。
#include
int main()
{
int T;
for (scanf("%d",&T);T--;) printf("0\n");
}
将所有活动按结束时间升序排序,遍历所有活动,如果可以参加活动i,则必然参加,ans++。输出ans。
下面对于正确性进行感性认知证明。
排序后,我们遍历整个数组,此时对于可以被选择的两个活动(即发生时间与其他已经选择了的活动没有交集),它们的发生时间必然为以下三种情况:
对于第一种情况,两个活动没有交集,不影响彼此是否被选择。
对于第二种情况,由于两个活动都可以被选择,所以活动二开始之前一定没有活动正在举行,我们可以忽略掉活动一举行到活动二举行这一段时间,变为第三种情况。
对于第三种情况,选择活动二必然更优(对其他活动的选择影响更小)。
综上,我们的选择策略没有问题。
#include
#include
struct asdf{
int a,b;
}a[1000001];
int n,x,ans;
int cmp(asdf a,asdf b)
{
return a.b<b.b;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d %d",&a[i].a,&a[i].b);
std::sort(a+1,a+1+n,cmp);
for (int i=1;i<=n;++i)
if (x<a[i].a) ans++,x=a[i].b;
printf("%d",ans);
}
数据范围较小,我们可以用二维数组存储整张地图,进行dfs。
因为这个dfs很裸我不知道该怎么bb,可以看代码把数据代入手玩一下。
#include
#define max(a,b) (a>b?a:b)
int n,m,q,a[1005][1005],v[1001][1001][2],ans[5001],t,maxx;
void dfs(int x,int y,int z)
{
if (a[x][y]==1)
{
v[x][y][0]=v[x][y][1]=t;
if (x>1&&!v[x-1][y][0]) dfs(x-1,y,0);
if (x<n&&!v[x+1][y][0]) dfs(x+1,y,0);
if (y>1&&!v[x][y-1][1]) dfs(x,y-1,1);
if (y<m&&!v[x][y+1][1]) dfs(x,y+1,1);
}
else
{
v[x][y][z]=t;
if (z==0)
{
if (x>1&&!v[x-1][y][0]) dfs(x-1,y,0);
if (x<n&&!v[x+1][y][0]) dfs(x+1,y,0);
}
else
{
if (y>1&&!v[x][y-1][1]) dfs(x,y-1,1);
if (y<m&&!v[x][y+1][1]) dfs(x,y+1,1);
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
for (int i=1;i<=q;++i)
{
int x,y;
scanf("%d%d",&x,&y);
a[x][y]=1;
}
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
if (a[i][j]==1)
{
if (v[i][j][0]) ans[v[i][j][0]]++;
else ans[++t]=1,dfs(i,j,2);
}
for (int i=1;i<=t;++i) maxx=max(maxx,ans[i]);
printf("%d",maxx);
}
睡眠时间小于一天,所以年月日可以忽略掉(
直接做差就好。
这个题wa了应该去面壁。
#include
int main()
{
int n,ay,am,ad,ah,amin,as,by,bm,bd,bh,bmin,bs;
for (scanf("%d",&n);n--;)
{
scanf("%d%d%d%d%d%d%d%d%d%d%d%d",&ay,&am,&ad,&ah,&amin,&as,&by,&bm,&bd,&bh,&bmin,&bs);
if (bs<as) bs=bs+60-as,bmin--;
else bs-=as;
if (bmin<amin) bmin=bmin+60-amin,bh--;
else bmin-=amin;
if (bh<ah) bh=bh+24-ah,bd--;
else bh-=ah;
printf("%d %d %d\n",bh,bmin,bs);
}
}
尽可能跳到跳跃范围内最远的荷叶上。
将荷叶按距离岸边从小到大排序,排好序后从第一片荷叶开始遍历所有荷叶,记录青蛙跳了ans步时距离岸边的最大距离m。如果青蛙无法不经过当前荷叶就跳到下一片荷叶,ans++,青蛙跳到当前荷叶上。如果青蛙无法跳到当前荷叶上,输出无解结束程序。
最后判断青蛙能否跳上对岸,若能,输出ans+1。
#include
#include
using namespace std;
int n,a[100001],x,m,ans;
int main()
{
scanf("%d%d",&x,&n);
n++;
for (int i=1;i<=n;++i) scanf("%d",&a[i]);
sort(a+1,a+n);
for (int i=1;i<n;++i)
{
if (a[i]>m+x) return printf("-1\n"),0;
if (a[i+1]>m+x) m=a[i],ans++;
}
if (a[n]>m+x) printf("-1");
else printf("%d",ans+1);
return 0;
}
动态规划。
给定数组x[i]。
状态:开一个数组f[i],记录前i个数的最美后缀和。
转移:f[i]=max(f[i-1]+a,a)
初状态:f[1]=x[1] //个人喜欢数组从1开始用
答案:max{f[i]}
然而正解是贪心。
用一个sum记录当前前缀和,遍历整个数组,如果前缀和sum变成了负数,当前数就不需要加上前面的数了(还不如只选它自己),这时把sum置为0,再继续累加。
这个问题通常被称为最大子段和问题。
#include
int main()
{
int n;
long long sum=-2147483648,ans=-2147483648,a;
for (scanf("%d",&n);n--;)
{
scanf("%lld",&a);
if (sum<0) sum=a;
else sum+=a;
if (ans<sum) ans=sum;
}
printf("%lld",ans);
}