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 ",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 ",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 ",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 "); }else{ printf("yes "); } } }
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 ",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 ",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,&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 ",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; } } } } } } }