前言:这套题目到处都找不到,csu上面也提交不了。最后在湖南师大oj找到了,可是这个师大oj实在是不好用,每次提交都要重新登录不说,还不支持lld,还我浪费好多时间去改WA。
思路:数据量比较小,直接暴力求解即可。
代码:
#include
#include
#include
#include
#include
#include
思路:细心模拟题,数组模拟链表的操作即可,第三个操作极其麻烦,要细心点。
对于第四个操作,其实注意x和y是原序列的下标,所以序列反了和没反对于1,2操作只是x插在y的左右反向反了而已,第三个操作就无影响了
代码:
#include
#include
#include
using namespace std;
#define N 100050
struct Node
{
int qian,hou;
} p[N];
void init(int n)
{
p[1].qian=-1;
p[n].hou=-1;
for(int i=2; i<=n; i++)
p[i].qian=i-1;
for(int i=1; i
思路:直接比较即可
代码:
#include
#include
#include
#include
#include
#include
题意:有n个城市和m条路,现在要从s到t,保证可以走到
所以得路都有一个通过时间,但是路本身会开启a时间,关闭b时间这样反复循环,求从s到t的最短时间
思路:一开始以为很复杂,其实就是一个最短路的问题,只不过加了点限制而已,不会影响s到t的最短距离。
用dijkstra或者spfa都可以
代码:
#include
#include
#include
#include
#include
#include
using namespace std;
#define INF 999999999
struct Edge
{
int v,next;
int a,b,t;
} edge[50050];
int cnt,head[305];
int n,m,s,e;
int vis[305],d[305];
void addedge(int u,int v,int a,int b,int t)
{
edge[cnt].v=v,edge[cnt].a=a,edge[cnt].b=b,edge[cnt].t=t;
edge[cnt].next=head[u],head[u]=cnt++;
}
void init()
{
cnt=0;
memset(head,-1,sizeof(head));
}
void spfa()
{
for(int i=1; i<=n; i++)
d[i]=INF;
memset(vis,0,sizeof(vis));
d[s]=0;
vis[s]=1;
queueque;
que.push(s);
while(!que.empty())
{
int now=que.front();
que.pop();
vis[now]=0;
for(int i=head[now]; i!=-1; i=edge[i].next)
{
int v=edge[i].v,a=edge[i].a,b=edge[i].b,t=edge[i].t;
int p=d[now]%(b+a),dis;
if (p>a) dis=d[now]+a+b-p+t;
else if(a-pdis)
{
d[v]=dis;
if(!vis[v])
{
que.push(v);
vis[v]=1;
}
}
}
}
}
int main()
{
//freopen("f.in","r",stdin);
//freopen("f.txt","w",stdout);
int u,v,a,b,t;
int tot=1;
while(scanf("%d %d %d %d",&n,&m,&s,&e)!=EOF)
{
init();
while(m--)
{
scanf("%d %d %d %d %d",&u,&v,&a,&b,&t);
if(t>a) continue;
addedge(u,v,a,b,t);
}
spfa();
printf("Case %d: %d\n",tot++,d[e]);
}
return 0;
}
思路:对于某个位置只要往左右两边找到最近的名字,比较一下距离即可
代码:
#include
#include
#include
using namespace std;
const int maxn = 105;
int n,m,L[maxn],R[maxn];
char str[maxn][5];
int main()
{
scanf("%d",&n);
for(int i = 1; i <= n; i++)
scanf("%s",str[i]);
memset(L,-1,sizeof(L));
memset(R,-1,sizeof(R));
for(int i = 1; i <= n; i++)
if(str[i][0] != '?')
L[i] = i;
else L[i] = L[i-1];
for(int i = n; i >= 1; i--)
if(str[i][0] != '?')
R[i] = i;
else R[i] = R[i+1];
scanf("%d",&m);
while(m--)
{
int k;
scanf("%d",&k);
if(str[k][0] != '?') printf("%s\n",str[k]);
else
{
if(L[k] == -1)
{
int cnt = R[k] - k + 1;
for(int i = 1; i < cnt; i++)
printf("left of ");
printf("%s\n",str[R[k]]);
continue;
}
if(R[k] == -1)
{
int cnt = k - L[k] + 1;
for(int i = 1; i < cnt; i++)
printf("right of ");
printf("%s\n",str[L[k]]);
continue;
}
if(k - L[k] + 1 == R[k] - k + 1)
printf("middle of %s and %s\n",str[L[k]],str[R[k]]);
else if(k - L[k] + 1 < R[k] - k + 1)
{
int cnt = k - L[k] + 1;
for(int i = 1; i < cnt; i++)
printf("right of ");
printf("%s\n",str[L[k]]);
}
else if(k - L[k] + 1 > R[k] - k + 1){
int cnt = R[k] - k + 1;
for(int i = 1; i < cnt; i++)
printf("left of ");
printf("%s\n",str[R[k]]);
}
}
}
return 0;
}
思路:每一次涨潮其实就是树状数组的一次区间变化,那么我们每次都去区间更新,最后求值即可
代码:
#include
#include
#include
#include
using namespace std;
const int maxn = 100005;
int n,m,k,tree[maxn<<1];
int h[maxn];
int lowbit(int x)
{
return x & -x;
}
void update(int x,int d)
{
while(x <= n)
{
tree[x] += d;
x += lowbit(x);
}
}
int sum(int x)
{
int ans = 0;
while(x > 0)
{
ans += tree[x];
x -= lowbit(x);
}
return ans;
}
int main()
{
int a,b,cas = 1;
while(scanf("%d %d %d",&n,&m,&k)!=EOF)
{
for(int i = 1; i <= n; i++)
scanf("%d",&h[i]);
memset(tree,0,sizeof(tree));
sort(h+1,h+1+n);
int pre = 1;
while(m--)
{
scanf("%d %d",&a,&b);
int pos = lower_bound(h+1,h+1+n,1 + a) - h;
update(pre,1);
update(pos,-1);
pre = lower_bound(h+1,h+1+n,b+1) - h;
}
int ans = 0;
for(int i = 1; i <= n; i++)
{
int cnt = sum(i);
if(cnt >= k)
ans++;
}
printf("Case %d: %d\n",cas++,ans);
}
return 0;
}
题意:给两个数x,y
再给一个3*10的矩阵,第一行表示在数的末尾加上0~9所需要的花费
第二行表示当前数加上0~9所需要的花费
第三行表示当前数*0~9所需要的花费
问从x->y的最小花费,以及在最小花费的情况下的最小操作次数
思路:dp[i]表示凑到i这个数所需要的最小花费,三重循环去转移即可。
转移的过程中用一个num数组去记录最小操作次数即可
代码:
#include
#include
#include
using namespace std;
const int inf = 999999999;
int n,m;
int cost[4][10];
int dp[100005],num[100005];
int main()
{
int cas = 1;
while(scanf("%d %d",&n,&m)!=EOF)
{
for(int i = 1; i <= 3; i++)
for(int j = 0; j <= 9; j++)
scanf("%d",&cost[i][j]);
for(int i = 0; i <= m; i++)
dp[i] = num[i] = inf;
dp[n] = 0;
num[n] = 0;
if(n != 0)
{
dp[0] = cost[3][0];
num[0] = 1;
}
for(int k = 0; k <= m; k++)
for(int i = 1; i <= 3; i++)
for(int j = 0; j <= 9; j++)
{
if(i == 1)
{
int tmp = k % 10; //取出个位
if(tmp != j) continue;
tmp = k / 10;
if(dp[k] > dp[tmp] + cost[i][j])
{
dp[k] = dp[tmp] + cost[i][j];
num[k] = num[tmp] + 1;
}
else if(dp[k] == dp[tmp] + cost[i][j])
num[k] = min(num[k],num[tmp]+1);
}
else if(i == 2)
{
int tmp = k - j;
if(tmp < 0) continue;
if(dp[k] > dp[tmp] + cost[i][j])
{
dp[k] = dp[tmp] + cost[i][j];
num[k] = num[tmp] + 1;
}
else if(dp[k] == dp[tmp] + cost[i][j])
num[k] = min(num[k],num[tmp]+1);
}
else
{
if(j == 0) continue;
if(k % j == 0)
{
int tmp = k / j;
if(dp[k] > dp[tmp] + cost[i][j])
{
dp[k] = dp[tmp] + cost[i][j];
num[k] = num[tmp] + 1;
}
else if(dp[k] == dp[tmp] + cost[i][j])
num[k] = min(num[k],num[tmp]+1);
}
}
}
printf("Case %d: %d %d\n",cas++,dp[m],num[m]);
}
return 0;
}
思路:直接暴力枚举a和b即可
代码:
#include
#include
#include
#include
#include
using namespace std;
int main()
{
long long x,y;
int tot=1;
while(scanf("%I64d %I64d",&x,&y)!=EOF)
{
long long ans=0;
for(long long i=x; i*i*i<=y*10+3; i++)
{
for(long long j=i; j*j*j<=y*10+3; j++)
{
long long m=i*i*i+j*j*j;
if(m%10==3&&m/10>=x&&m/10<=y)
ans++;
}
}
printf("Case %d: %I64d\n",tot++,ans*2);
}
return 0;
}