ACM-ICPC 2018 南京賽區網路預賽---總結
阿新 • • 發佈:2018-12-24
ACM-ICPC 2018 南京賽區網路預賽
總結 與ldq隊差距 4題
A 水題 輸出 n-1
B:發現了一篇很好的部落格,講得很好
連結
類似題 :
51nod 1291 Farmer
EOJ 3514. 五彩地磚
Wannafly挑戰賽12 D
。。。。。。
my_code
#include<bits/stdc++.h>
using namespace std;
const int N = (1<<20)+5;
const long long inf =1e18;
typedef long long ll;
struct node
{
ll a,b;
int pre;
} p[N];
ll dp[N];
int main()
{
int n;
cin>>n;
for(int i=1; i<=n; i++)
{
scanf("%lld%lld",&p[i].a,&p[i].b);
int vc;
scanf("%d",&vc);
while(vc--)
{
int y;
scanf ("%d",&y);
p[i].pre=p[i].pre|(1<<(y-1));
}
}
int nn = 1<<n;
for(int i=0; i<nn; i++)dp[i] = -inf;
dp[0]= 0;
ll ans = 0;
for(int i=0; i<nn; i++)
{
if(dp[i]==-inf)continue;
ll t = 1;
for(int j=1; j<=n; j++)
{
if (i&(1<<(j-1)))t++;
}
for(int j=1; j<=n; j++)
{
if(i&(1<<(j-1)))continue;
if(p[j].pre==0||(p[j].pre&i)>=p[j].pre)
{
int nxt= i|(1<<(j-1));
dp[nxt] = max(dp[nxt],p[j].a*t+p[j].b+dp[i]);
ans= max(ans,dp[nxt]);
}
}
}
cout<<ans<<endl;
return 0;
}
I 裸的迴文樹 ,最近一直在刷這個專題,可惜了 前期題卡到最後
注意N = 10,只有10個字元,只開一個迴文樹就可以。
my_code:
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
const int MAXN = 2000008 ;
ll Pow[MAXN];
ll dp[MAXN];
char a[2000008];
const int N = 11 ;
long long ans;
struct Palindromic_Tree {
int next[MAXN][N] ;//next指標,next指標和字典樹類似,指向的串為當前串兩端加上同一個字元構成
int fail[MAXN] ;//fail指標,失配後跳轉到fail指標指向的節點
long long cnt[MAXN];
int len[MAXN] ;//len[i]表示節點i表示的迴文串的長度
int S[MAXN] ;//存放新增的字元
int last ;//指向上一個字元所在的節點,方便下一次add
int n ;//字元陣列指標
int p ;//節點指標
int length[MAXN] ;
int newnode ( int l ) {//新建節點
for ( int i = 0 ; i < N ; ++ i ) next[p][i] = 0 ;
cnt[p] = 0 ;
// num[p] = 0 ;
len[p] = l ;
return p ++ ;
}
void init () {//初始化
p = 0 ;
newnode ( 0 ) ;
newnode ( -1 ) ;
last = 0 ;
n = 0 ;
S[n] = -1 ;//開頭放一個字符集中沒有的字元,減少特判
fail[0] = 1 ;
}
int get_fail ( int x ) {//和KMP一樣,失配後找一個儘量最長的
while ( S[n - len[x] - 1] != S[n] ) x = fail[x] ;
return x ;
}
void add ( ll c ) {
c -= '0' ;
S[++ n] = c ;
int cur = get_fail ( last ) ;//通過上一個迴文串找這個迴文串的匹配位置
if ( !next[cur][c] ) {//如果這個迴文串沒有出現過,說明出現了一個新的本質不同的迴文串
int now = newnode ( len[cur] + 2 ) ;//新建節點
fail[now] = next[get_fail ( fail[cur] )][c] ;//和AC自動機一樣建立fail指標,以便失配後跳轉
if(cur==1)
{
length[now] = 1;
dp[now] =c;
}
else if(cur==0)
{
length[now] = 2;
dp[now] = c*10+c;
}
else
{
length[now] = length[cur]+2;
dp[now] = (dp[cur]*10%mod+c*Pow[length[cur]+2]%mod+c)%mod;
}
ans+=dp[now];
ans%=mod;
next[cur][c] = now ;
// num[now] = num[fail[now]] + 1 ;
}
last = next[cur][c] ;
cnt[last] ++ ;
}
} ;
Palindromic_Tree a1;
int main()
{
Pow[1] = 1;
for(int i=2;i<=MAXN;i++)
{
Pow[i] = (Pow[i-1]*10)%mod;
}
a1.init();
scanf("%s",a);
int len= strlen(a);
ans = 0;
for(int i=0;i<len;i++)
{
a1.add(a[i]);
}
printf("%lld\n",ans);
return 0;
}
G 有n間房間 每間房間有a[i]個燈泡,現在每天會買k個,有v個詢問,每次詢問第p天已經安裝好的房間數和剩餘的燈泡數,只有當前留有的燈泡數大於等於某一個房間的燈泡時才會進行安裝,安裝是按照輸入順序依次進行的。
用線段樹維護區間最小值+單點更新即可。
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lson rt<<1
#define rson rt<<1|1
#define MID int m = (l+r)/2;
const int N =200000;
struct node
{
int v;
} tree[N<<2];
int a[N],op[N],ans1[N],ans2[N];
void push_up(int rt)
{
tree[rt].v = min(tree[lson].v,tree[rson].v);
}
void update(int rt,int l,int r,int p,int val)
{
if(l==r&&l==p)
{
tree[rt].v = val;
return ;
}
MID
if(p<=m)update(lson,l,m,p,val);
else update(rson,m+1,r,p,val);
push_up(rt);
}
void build(int rt,int l,int r)
{
if(l>r)return;
if(l==r)
{
tree[rt].v = a[l];
return ;
}
MID
build(lson,l,m);
build(rson,m+1,r);
push_up(rt);
}
int query(int rt,int l,int r,int val)
{
if(l==r)return l;
MID
if(tree[lson].v<=val) return query(lson,l,m,val);
if(tree[rson].v<=val)return query(rson,m+1,r,val);
return -1;
}
int main()
{
int n,k;
cin>>n>>k;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
// update(1,1,n,i,a[i]);
}
build(1,1,n);
int v;
cin>>v;
int mx = 0;
for(int i=1; i<=v; i++)
{
scanf("%d",&op[i]);
mx = max(mx,op[i]);
}
int tt = 0;
int tmp = 0;
for(int i=1; i<=mx; i++)
{
tmp+=k;
while(1)
{
int h = query(1,1,n,tmp);
if(h==-1)
{
//tt++;
ans1[i] = tt;
ans2[i] = tmp;
break;
}
else
{
tt++;
tmp-=a[h];
ans1[i] = tt;
ans2[i] = tmp;
update(1,1,n,h,0x3f3f3f3f);
}
}
}
for(int i=1; i<=v; i++)
{
printf("%d %d\n",ans1[op[i]],ans2[op[i]]);
}
return 0;
}
my_code
#include<bits/stdc++.h>
using namespace std;
const int N = 2e7+2;
bool vis[N];
long long p[N],f[N];
void init()
{
int i,i1;
memset(vis,0,sizeof(vis));
f[1] = 1;
//f[0] =1;
int top=0;
for(i=2;N>=i;i++)
{
if(vis[i]==0)
{
p[top++]=i;
f[i] = 2;
}
for(i1=0;top>i1&&N>=p[i1]*i;i1++)
{
vis[i*p[i1]]=1;
if(i%p[i1])//i裡面沒有一個p[i1]因子
{
f[i*p[i1]] = f[p[i1]]*f[i];
}
else
{
//if(i%(p[i1]*p[i1]))
if((i/p[i1])%p[i1]==0)//i*p[i1]裡面有兩個及以上的因子
{
f[i*p[i1]] = 0;
}
else //i裡面僅有一個p[i1]因子
{
f[i*p[i1]] = f[i/p[i1]];
}
break;
}
}
}
// cout<<top-1<<endl;
for(int i=2;i<=N;i++)
{
f[i] = f[i-1]+f[i];
}
}
int main()
{
init();
int T;
cin>>T;
while(T--)
{
int n;cin>>n;
cout<<f[n]<<endl;
}
return 0;
}
看到了別人另一種做法,也挺好
部落格連結
https://blog.csdn.net/albertluf/article/details/82291234
L. Magical Girl Haze
把每個點拆成k+1個點建立分層圖,對於第i個點,拆成i,i+n,i+2*n...i+k*n
若原圖中i~j有一條權值為x的邊,則
add_edge(i,j,x),add_edge(i+n,j+n,x).....add_edge(i+k*n,j+k*n,x)
add_edge(i,j+n,0),add_edge(i+n,j+2*n,0)....add_edge(i+(k-1)*n,j+k*n,0)
每向上走一層相當於走了一條權值為0的邊,
假設走了(i,j+n,0)相當於從第0層走到了第一層,而把i~j這條邊的權值改為0。
最後輸出1~(k+1)*n的最短路即可。
my_code
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
long long dist[N][15];
const long long inf = 1e18+7;
typedef pair<int,long long >ppi;
int top,head[N*2];
int n,m,k;
struct node
{
int u,v;
long long w;
int next;
} edge[N*2];
struct pp{
int v;
long long w;
pp(int _v=0,long long _w=0):v(_v),w(_w){}
bool operator<(const pp&h)const
{
return w>h.w;
}
};
void addedge(int u,int v,long long w)
{
edge[top].v = v;
edge[top].w = w;
edge[top].next = head[u];
head[u] = top++;
}
void dijkstra()
{
priority_queue<pp>o;
for(int i=1; i<=n; i++)
{
for(int j=0; j<=12; j++)
{
dist[i][j] = inf;
}
}
for(int i=0; i<=10; i++)
{
dist[1][i] = 0;
}
o.push(pp(1,0));
while(!o.empty())
{
pp tmp =o.top();
// printf("%d%d\n",o.top().first,o.top().second);
o.pop();
int u = tmp.v;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
// printf("%d\n",i);
int v = edge[i].v;
long long w = edge[i].w;
if(dist[u][0]+w<dist[v][0])
{
dist[v][0] = dist[u][0]+w;
o.push(pp(v,dist[v][0]));
}
for(int j=1; j<=k; j++)
{
if(dist[u][j]+w<dist[v][j])
{
dist[v][j] = dist[u][j]+w;
o.push(pp(v,dist[v][j]));
}
if(dist[u][j-1]<dist[v][j])
{
dist[v][j] = dist[u][j-1];
o.push(pp(v,dist[v][j]));
}
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&k);
memset(head,-1,sizeof(head));
top = 0;
for(int i=1; i<=m; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
}
dijkstra();
// for(int i=1;i<=n;i++)
// {
// for(int j=0;j<=k;j++)
// {
// printf("%d ",dist[i][j]);
// }
// printf("\n");
// }
long long ans = inf;
for(int i=0;i<=k;i++)
{
ans = min(dist[n][i],ans);
}
printf("%lld\n",ans);
}
return 0;
}