Array Without Local Maximums
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100001;
const ll mod=998244353;
int n,a[maxn];
ll f[maxn][201][3],sum,ans;
int main()
{
scanf("%d",&n);
for (int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
}
for (int i=1; i<=200; i++)
{
if (a[1]!=-1&&a[1]!=i)
{
f[1][i][0]=f[1][i][1]=f[1][i][2]=0;
}
else
{
f[1][i][0]=1;
f[1][i][1]=0;
f[1][i][2]=0;
}
}
for (int i=2; i<=n; i++)
{
sum=0;
for (int j=1; j<=200; j++)
{
if (a[i]!=-1&&a[i]!=j)
{
f[i][j][0]=0;
}
else
{
f[i][j][0]=sum;
}
sum=(sum+f[i-1][j][0]+f[i-1][j][1]+f[i-1][j][2])%mod;
}
for (int j=1; j<=200; j++)
{
if (a[i]!=-1&&a[i]!=j)
{
f[i][j][1]=0;
}
else
{
f[i][j][1]=(f[i-1][j][0]+f[i-1][j][1]+f[i-1][j][2])%mod;;
}
}
sum=0;
for (int j=200; j>=1; j--)
{
if (a[i]!=-1&&a[i]!=j)
{
f[i][j][2]=0;
}
else
{
f[i][j][2]=sum;
}
sum=(sum+f[i-1][j][1]+f[i-1][j][2])%mod;
}
}
for (int i=1; i<=200; i++)
{
ans=(ans+f[n][i][2]+f[n][i][1])%mod;
}
printf("%lld\n",ans);
}
Shell Pyramid
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll i,j,k,n;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%lld",&n) ;
i = (ll)(pow(double(n) * 6.0,1.0/3.0))-1;
while(i*(i+1)/2*(i+2)/3 < n )
{
i ++ ;
}
n -= (i-1)*(i)/2*(i+1)/3 ;
j = (ll)(sqrt(n * 2.0)) ;
while(j * (j+1)/2 < n)
j ++ ;
n -=j*(j-1)/2 ;
k= n;
printf("%lld %lld %lld\n",i,j,k) ;
}
return 0;
}
Gauss Elimination
import java.util.*;
import java.math.*;
public class Main
{
public static BigInteger g[][] = new BigInteger[110][110];
public static boolean Gauss_Elimination(int n)
{
BigInteger tmp,a,b;
int i,j,k;
for (i=0; i<n; i++)
{
for (j=i; j<n; j++)
{
if (g[j][i].compareTo(BigInteger.ZERO)!=0)
{
break;
}
}
if (j>=n)
{
return false;
}
if (i!=j)
{
for (k=0; k<=n; k++)
{
tmp=g[i][k];
g[i][k]=g[j][k];
g[j][k]=tmp;
}
}
a=g[i][i];
for (j=i+1; j<n; j++)
{
if (g[j][i].compareTo(BigInteger.ZERO)!=0)
{
b=g[j][i];
for (k=i; k<=n; k++)
{
g[j][k]=g[j][k].multiply(a).subtract(g[i][k].multiply(b));
}
}
}
}
return true;
}
public static void main (String[] args)
{
Scanner cin = new Scanner(System.in);
BigInteger x[]= new BigInteger[110];
BigInteger y[]= new BigInteger[110];
BigInteger tmp,up,down;
int n,i,j;
boolean neg;
while (cin.hasNext())
{
n=cin.nextInt();
for (i=0; i<n; i++)
{
for (j=0; j<=n; j++)
{
g[i][j]=cin.nextBigInteger();
}
}
if (Gauss_Elimination(n))
{
for (i=n-1; i>=0; i--)
{
up=BigInteger.ZERO;
down=BigInteger.ONE;
for (j=i+1; j<n; j++)
{
up=y[j].multiply(up).add(g[i][j].multiply(x[j].multiply(down)));
down=y[j].multiply(down);
}
up=g[i][n].multiply(down).subtract(up);
down=g[i][i].multiply(down);
if (up.multiply(down).compareTo(BigInteger.ZERO)<0)
{
neg=true;
}
else
{
neg=false;
}
up=up.abs();
down=down.abs();
tmp=up.gcd(down);
x[i]=up.divide(tmp);
y[i]=down.divide(tmp);
if (neg)
{
x[i]=x[i].negate();
}
}
for (i=0; i<n; i++)
{
if (x[i].mod(y[i]).compareTo(BigInteger.ZERO)==0)
{
System.out.println(x[i].divide(y[i]));
}
else
{
System.out.println(x[i]+"/"+y[i]);
}
}
}
else
{
System.out.println("No solution.");
}
System.out.println();
}
}
}
Simple Addition expression
题意:给出数n,在区间[0,n]中取值i,使得 (i) + (i+1) + (i+2), i>=0间的计算不会产生进位
统计在小于n的情况下,有多少个i符合i+i+1+i+2没有进位
首先因为没有进位,那么能够确定除了个位之外所有是0~3
而个位因为加了3,那么个位仅仅能是0~2
然后又研究了好一会才知道什么解,个位数不能超过2,其他位数不超过3即可:即个位最大为3,其他位最大为4.把这个数当做字符串就好解决了,从这个字符串的第一位开始判断就可以了……然后计算这些排列数就行了。如果为个数,就直接加上,如果有其他位数,那先判断第一位,如果大于3就可以直接用相乘,如果小于3的话,那这位数之前的可以直接相乘,这位数的情况就往下位数继续判断……这样依次判断到最后个位数就行了……把这些结果相加就得到结果了。
#include<bits/stdc++.h>
using namespace std;
char a[100];
typedef long long ll;
ll sum,c;
int main()
{
while (~scanf("%s",a))
{
sum=0;
int len=strlen(a);
for (int i=0; i<len; i++)
{
c=a[i]-'0';
if (i==len-1)
{
if (c<3)
{
sum+=c;
}
else
{
sum+=3;
}
break;
}
if (c<4)
{
sum+=c*pow(4,len-i-2)*3;
}
else
{
sum+=pow(4,len-i-1)*3;
break;
}
}
printf("%lld\n",sum);
}
}
Degree Sequence of Graph G
#include<bits/stdc++.h>
using namespace std;
priority_queue<int>q;
int a[100000],n,x,f;
int main(){
int T;
scanf("%d",&T);
while (T--){
f=0;
while (!q.empty()){
q.pop();
}
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d",&x);
if (x) q.push(x);
}
while (!q.empty()){
x=q.top();
q.pop();
if (x>q.size()){
f=1;
break;
}
for (int i=1;i<=x;i++){
a[i]=q.top()-1;
q.pop();
}
for (int i=1;i<=x;i++){
if (a[i]){
q.push(a[i]);
}
}
}
if (f){
printf("no\n");
}else{
printf("yes\n");
}
}
}
Navy maneuvers
#include<bits/stdc++.h>
using namespace std;
const int maxn=10010;
int f[10010][2],in[maxn],w[maxn],m,n,ff;
vector<int>E[maxn];
int dfs(int cur,int turn){
if (f[cur][turn&1]!=-1){
return f[cur][turn&1];
}
if (E[cur].size()==0){
return f[cur][turn&1]=w[cur];
}
f[cur][turn&1]=0;
int len=E[cur].size(),mn=0x3f3f3f3f,mx=-0x3f3f3f3f;
for (int i=0;i<len;i++){
int to = E[cur][i];
if (turn&1){
mx=max(mx,dfs(to,turn+1));
}else{
mn=min(mn,dfs(to,turn+1));
}
}
if (turn&1){
return f[cur][turn&1]=w[cur]+mx;
}else{
return f[cur][turn&1]=w[cur]+mn;
}
}
int main()
{
while (~scanf("%d%d%d",&n,&m,&ff))
{
memset(f,-1,sizeof (f));
for (int i=1; i<=n; i++)
{
in[i]=0;
E[i].clear();
}
int ans=0;
for (int i=1; i<=n; i++)
{
scanf("%d",&w[i]);
}
for (int i=1,u,v; i<=m; i++)
{
scanf("%d%d",&u,&v);
E[u].push_back(v);
in[v]++;
}
for (int i=1; i<=n; i++)
{
if (!in[i])
{
ans=max(ans,dfs(i,1));
}
}
if (ans>=ff)
{
puts("Victory");
}
else
{
puts("Glory");
}
}
return 0;
}
Mining Station on the Sea
建图如下:
①建立源点S,将其连入各个船所在的点,权值设定为1,费用设定为0,表示只有一个船.
②建立汇点T,将各个港口连入汇点T,权值设定为1,费用设定为0,表示只能停一个船.
③将m条无向边直接建立起来,权值设定为其距离,费用设定为INF。表示可以走无数次。
④将p条有向边直接建立起来,将点连入港口,权值设定为其距离,费用设定为1。
#include <bits/stdc++.h>
using namespace std;
const int maxm=2000000;
const int maxn=330;
const int inf=0x3f3f3f3f;
typedef pair<int,int> PI;
struct MCFC {
struct edge {
int to, next, cap, flow, cost;
} e[maxm];
int head[maxn], tol;
int pre[maxn], dis[maxn];
bool vis[maxn];
int N;
void init(int n) {
N = n;
tol = 1;
memset(head, 0, sizeof(head));
}
void addedge(int u, int v, int cap, int cost) {
tol++;
e[tol].to = v;
e[tol].cap = cap;
e[tol].cost = cost;
e[tol].flow = 0;
e[tol].next = head[u];
head[u] = tol;
tol++;
e[tol].to = u;
e[tol].cap = 0;
e[tol].flow = 0;
e[tol].cost = -cost;
e[tol].next = head[v];
head[v] = tol;
}
bool spfa(int s, int t) {
queue<int> q;
for (int i = 0; i <= N; i++) {
dis[i] = inf;
vis[i] = false;
pre[i] = -1;
}
dis[s] = 0;
vis[s] = true;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
vis[u] = false;
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
if (e[i].cap > e[i].flow && dis[v] >dis[u] + e[i].cost) {
dis[v] = dis[u] + e[i].cost;
pre[v] = i;
if (!vis[v]) {
vis[v] = true;
q.push(v);
}
}
}
}
if (pre[t] == -1) return false;
else return true;
}
int cost = 0;
PI mcmf(int s, int t) {
int flow = 0;
cost = 0;
while (spfa(s, t)) {
int minn = inf;
for (int i = pre[t]; i != -1; i = pre[e[i ^ 1].to]) {
if (minn > e[i].cap - e[i].flow) {
minn = e[i].cap - e[i].flow;
}
}
for (int i = pre[t]; i != -1; i = pre[e[i ^ 1].to]) {
e[i].flow += minn;
e[i ^ 1].flow -= minn;
cost += e[i].cost * minn;
}
flow += minn;
}
return make_pair(cost,flow);
}
} G;
int main(){
int n,m,k,p,T,S,pos,u,v,w;
while (~scanf("%d%d%d%d",&n,&m,&k,&p)){
T=n+m+1;
S=0;
G.init(T);
for (int i=1;i<=n;i++){
scanf("%d",&pos);
G.addedge(S,pos,1,0);
}
for (int i=1;i<=n;i++){
G.addedge(m+i,T,1,0);
}
for (int i=1;i<=k;i++){
scanf("%d%d%d",&u,&v,&w);
G.addedge(u,v,inf,w);
G.addedge(v,u,inf,w);
}
for (int i=1;i<=p;i++){
scanf("%d%d%d",&u,&v,&w);
G.addedge(v,u+m,1,w);
}
printf("%d\n",G.mcmf(S,T).first);
}
}
#include <bits/stdc++.h>
using namespace std;
const int maxm=900000;
const int maxn=330;
const int inf=0x3f3f3f3f;
typedef pair<int,int> PI;
struct Min_Cost_Max_Flow{
struct edge{
int to,cap,cost,rev;
edge(){};
edge(int _to,int _cap,int _cost,int _rev):to(_to),cap(_cap),cost(_cost),rev(_rev){};
};
vector<edge>E[maxm];
int h[maxn],n,d[maxn],preV[maxn],preE[maxn];
void init(int n){
this->n=n;
for (int i=0;i<=n;i++){
E[i].clear();
h[i]=0;
}
}
void add(int from,int to,int cap,int cost){
E[from].push_back(edge(to,cap,cost,E[to].size()));
E[to].push_back(edge(from,0,-cost,E[from].size()-1));
}
PI dijkstra(int s,int t,int f){
int cost=0,flow=0;
for (int i=0;i<=n;i++){
h[i]=0;
}
while (f){
priority_queue<PI,vector<PI>,greater<PI> >q;
for (int i=0;i<=n;i++){
d[i]=inf;
}
d[s]=0;
q.push(make_pair(0,s));
while (!q.empty()){
PI now=q.top();
q.pop();
int v=now.second;
if (d[v]<now.first){
continue;
}
for (int i=0;i<E[v].size();i++){
edge &e=E[v][i];
if (e.cap>0&&d[e.to]>d[v]+e.cost+h[v]-h[e.to]){
d[e.to]=d[v]+e.cost+h[v]-h[e.to];
preV[e.to]=v;
preE[e.to]=i;
q.push(make_pair(d[e.to],e.to));
}
}
}
if (d[t]==inf)break;
for (int i=0;i<=n;i++){
h[i]+=d[i];
}
int d=f;
for (int i=t;i!=s;i=preV[i]){
d=min(d,E[preV[i]][preE[i]].cap);
}
f-=d;
flow+=d;
cost+=d*h[t];
for (int i=t;i!=s;i=preV[i]){
edge &e=E[preV[i]][preE[i]];
e.cap-=d;
E[i][e.rev].cap+=d;
}
}
return make_pair(flow,cost);
}
}G;
int main(){
int n,m,k,p,T,S,pos,u,v,w;
while (~scanf("%d%d%d%d",&n,&m,&k,&p)){
T=n+m+1;
S=0;
G.init(T);
for (int i=1;i<=n;i++){
scanf("%d",&pos);
G.add(S,pos,1,0);
}
for (int i=1;i<=n;i++){
G.add(m+i,T,1,0);
}
for (int i=1;i<=k;i++){
scanf("%d%d%d",&u,&v,&w);
G.add(u,v,inf,w);
G.add(v,u,inf,w);
}
for (int i=1;i<=p;i++){
scanf("%d%d%d",&u,&v,&w);
G.add(v,u+m,1,w);
}
printf("%d\n",G.dijkstra(S,T,inf).second);
}
}
Carrying Out A Task
简述一下题意:
20*20的地图上,一个起点S,一个终点E,障碍物#,漩涡*
一艘船从起点出发,携带充足的A类油和X升B类油。
沿上下左右四个方向行驶,不能在障碍物的格子行驶;可以进入漩涡,但每次进入船会受伤。没走过一个格子都要消耗一升A类油。
每个回合有两个操作:
1.普通航行一格
2.加速一次消耗Y升B类油,有两种加速方法,加速规则:
a.在某一个方向连续航行d步,d步之内不能有障碍物、漩涡,不能驶出地图
b.当下一步要驶入漩涡时,必须加速、进入漩涡后加速效果消失
询问船是否可以到达终点,输出最少多少个回合到达,前提——船受到的伤害最小(进入漩涡次数最少),其次消耗A类油最少(走过的格子数最少),再次回合数最少。
简述方法:限制条件的SPFA。用优先队列,不断更新符合要求的最短路径。
利用num[横坐标][纵坐标][受伤次数] 来记录所剩余的最大加速次数,如果后来者所存有的加速次数比先到者的多,就再走一遍。
利用优先队列,按照 1. 受伤次数最少 、 2. 耗A量最少 、3. 步数最少 ,按顺序进行优先级排序,依次最少的先出队列
这里有两个比较好的剪枝:
1. 先搜索一遍,能否到达终点
2. num[x][y][当前受伤次数-1]的位置如果已经走过,就不再走,既然少受伤一次能都路过,现在就不必再走了
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=22;
const int fy[]={0,0,-1,1};
const int fx[]={1,-1,0,0};
struct Point{ // damage ,B-cost,A-cost
int x,y,step,dmg,bcst,acst;
Point(){}
Point(int tx,int ty,int ts,int td,int ta,int tb){
x=tx,y=ty,step=ts,dmg=td,acst=ta,bcst=tb;
}
bool friend operator<(Point p,Point q){
if(p.dmg!=q.dmg) return p.dmg>q.dmg;
if(p.acst!=q.acst) return p.acst>q.acst;
return p.step>q.step;
}
};
struct Cdnt{ // Coordinate
int x,y,cst;
Cdnt(){};
Cdnt(int tx,int ty,int tc){x=tx,y=ty,cst=tc;}
bool friend operator<(Cdnt p,Cdnt q){
return p.cst>q.cst;
}
};
char mp[maxn][maxn];
int n,m,sx,sy,dis;
int CBA(){ // E can be arrived ? Return the number of damage.
int k;
bool vis[maxn][maxn];
Cdnt now,next;
priority_queue<Cdnt>q;
memset(vis,false,sizeof(vis));
q.push(Cdnt(sx,sy,0));
vis[sx][sy]=true;
while(!q.empty()){
now=q.top();
q.pop();
if(mp[now.x][now.y]=='E') return now.cst;
for(k=0;k<4;k++){
next.x=now.x+fx[k];
next.y=now.y+fy[k];
if(next.x<0 || next.x>=n || next.y<0 || next.y>=m) continue;
if(vis[next.x][next.y] || mp[next.x][next.y]=='#') continue;
if(mp[next.x][next.y]=='*') next.cst=now.cst+1;
else next.cst=now.cst;
vis[next.x][next.y]=true;
q.push(next);
}
}
return -1;
}
priority_queue<Point>que;
short num[maxn][maxn][maxn*maxn]; // [x][y][number of undercurrent] for accelerate
void init_(int res){
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
for(int k=0;k<=res;k++)
num[i][j][k]=-1;
while(!que.empty()) que.pop();
}
int bfs(int v){ // v -> The number of total acceleration.
int res,k,z;
Point now,next;
res=CBA();
if(res==-1 || res>v) return -1;
init_(res+1);
que.push(Point(sx,sy,0,1,0,v));
num[sx][sy][1]=v;
while(!que.empty()){
now=que.top();
que.pop();
// cout<<now.x<<" "<<now.y<<endl;
if(mp[now.x][now.y]=='E') return now.step;
for(k=0;k<4;k++){
if(now.bcst>res-now.dmg){
next=now;
for(z=0;z<dis;z++){
next.x+=fx[k];
next.y+=fy[k];
if(next.x>=n || next.y>=m || next.x<0 || next.y<0) break;
if(mp[next.x][next.y]=='#' || mp[next.x][next.y]=='*') break;
}
if(z==dis){
next.step++;
next.bcst--;
next.acst+=dis;
if(num[next.x][next.y][next.dmg]<next.bcst && num[next.x][next.y][next.dmg-1]==-1){
num[next.x][next.y][next.dmg]=next.bcst;
que.push(next);
}
}
}
next=now;
next.x+=fx[k];
next.y+=fy[k];
next.step++;
next.acst++;
if(next.x>=n || next.y>=m || next.x<0 || next.y<0) continue;
if(mp[next.x][next.y]=='#') continue;
if(mp[next.x][next.y]=='*'){
if(next.bcst>0) next.bcst--,next.dmg++;
else continue;
}
if(num[next.x][next.y][next.dmg]<next.bcst && num[next.x][next.y][next.dmg-1]==-1){
num[next.x][next.y][next.dmg]=next.bcst;
que.push(next);
}
}
}
return -1;
}
int main(){
int t,i,j,res;
scanf("%d",&t);
while(t--){
scanf("%d%d\n",&n,&m);
for(i=0;i<n;i++){
gets(mp[i]);
for(j=0;j<m;j++)
if(mp[i][j]=='S')
sx=i,sy=j;
}
scanf("%d",&dis);
scanf("%d%d",&i,&j);
res=bfs(i/j);
if(res==-1) puts("can not reach!");
else printf("%d\n",res);
}
return 0;
}
K-dimension number
题意:定义K-维数M:如果M的因数个数为K,则M为K-维数。题目的要求是求第N个K-维数。N<10000,Kmax<=100,Kmax是K的最大质因数。如果K是一个kk-维数,则kk<=3。
分析:
如果M = x1^p1 * x2^p2 * ... * xn^pn (x1,x2...xn均为质数),则 K = (p1+1)*(p2+1)*...*(pn+1).
这道题重要的条件是:如果K是一个kk-维数,则kk<=3。根据这个条件可以确定K的范围。kk的取值只有三种1,2,3。如果kk=1,则K=1;如果kk=2,K=p(p为质数);如果kk=3,K=p^2(p为质数)。
分情况讨论,如果K = 1,则原数M只可能为1,因为只有1的因数个数为1。如果K = p(p为质数),则原数M = x^(p-1)(x也为质数),找到第n个数只需遍历一下质数表就可以了。如果K=p^2(p为质数),则原数M = x1^(p-1)*x2^(p-1) = (x1*x2)^(p-1) (x1,x2均为质数且不等),或者 M = x1^(K-1) (x1为质数)。这种情况下找到第n个K-维数就比较复杂了,首先要找到前10000个两个不等质数之积,在对质数表和两个质数积表进行扫描,找到第n个值。
本题目是一个非常好的数学题,根据上面的三种情况主要有如下结论:
1.当k=1时,结果直接为1
2.当k=p时,结果为prime[n]^(k-1),这里的prime[n]为从2开始的第n个素数
3.当k=p^2时,结果为p^(k-1)和(p1*p2)^(p-1)之中的第n个数(这里p1,p2为任意素数)
当然知道结论是不够的,本题需要解决几个难点
1.大数,这里用java解决简单了许多
2.上述的情况三时,到底如何知道第n个数是什么呢?
3.不断的大数运算是否会超时???这里算阶乘的时候我们全部用log算!这样节约了很多时间空间!!!
为了解决第二个问题直观的想法就是暴力,但是绝对的超时,这个也是学到的最巧妙的一个思路。
首先我们在最最开始的时候需要得到一个至少长度为10000的素数表(情况二就会用到了),我们在考虑情况三时往往想p1,p2值是多少然后乘起来比较大小,那么换一种思路,假如我们知道一个数a,且知道该数的一个素数约数b,那么判断a/b是否为素数,如果是说明满足了条件。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
public static void main(String[] args){
final int N=105050;
int pnum=0;
int []prime = new int [10050];
int []pd = new int [N+5];
int cnt=0;
int []pl= new int [10050];
int n,k;
for (int i=1;i<=N;i++){
pd[i]=0;
}
for (int i=2;i<=N;i++){
if (pd[i]==0){
prime[++pnum]=pd[i]=i;
}
for (int j=1;j<=pnum&&i*prime[j]<=N;j++){
pd[i*prime[j]]=prime[j];
if (i%prime[j]==0){
break;
}
}
}
for (int i=6;i<=41200;i++){
int x=i/pd[i];
if (pd[i]!=x&&x==pd[x]){
pl[++cnt]=i;
}
}
Scanner cin = new Scanner(System.in);
while (cin.hasNext()){
n=cin.nextInt();
k=cin.nextInt();
int p1=0,p2=0;
for (int i=1;i<=pnum;i++){
if (k%prime[i]==0){
p1=prime[i];
p2=k/prime[i];
}
}
if (k==1){
System.out.println(1);
continue;
}
if (p2==1){
BigInteger temp=BigInteger.valueOf(prime[n]);
temp=temp.pow(k-1);
System.out.println(temp);
continue;
}
if (p1==p2){
int i=1,j=1;
while (true){
double x=(p1*p1-1)*Math.log10(prime[i]),y=(p1-1)*Math.log10(pl[j]);
BigInteger sum1=BigInteger.valueOf(prime[i]).pow(p1*p1-1),sum2=BigInteger.valueOf(pl[j]).pow(p1-1);
if (x<=y){
i++;
if (i+j-2==n){
System.out.println(sum1);
break;
}
}else{
j++;
if (i+j-2==n){
System.out.println(sum2);
break;
}
}
}
}
}
}
}