佛了佛了,這場模擬卡了三個小時,好不容易碰到一道費用流結果根本沒時間寫
Problem A CFGym 102801A Micro Structure Thread???
2 / 3 Problem B CFGym 102801B Team !!!
網絡流題目的常見套路,源點和b集合連邊,b集合和a集合連邊,a集合和c集合連邊,這樣就能保住必選三個人了,注意a集合在中間要拆點自己和自己的副本連一條流量1費用0的邊來現在a只用一次
這種套路洛谷上我就見到至少三個,好可惜啊
#include<stdio.h>
#include<vector>
#include<string.h>
#include<queue>
#define ll long long
#define mod 998244353
#define maxn 10033
using namespace std;
const ll inf=1e9;
#include<vector>
struct E
{
ll to,next,lim,cos;
}e[maxn*100];
ll head[maxn],cnt;
void add(ll u,ll v,ll lim,ll cos)
{
e[cnt].to=v;
e[cnt].lim=lim;
e[cnt].cos=cos;
e[cnt].next=head[u];
head[u]=cnt++;
e[cnt].to=u;
e[cnt].lim=0;
e[cnt].cos=-cos;
e[cnt].next=head[v];
head[v]=cnt++;
}
ll n,m,s,t;
queue<ll>q;
ll dis[maxn],flow[maxn],pre[maxn],vis[maxn];
ll bfs()
{
while(!q.empty()) q.pop();
q.push(s);
for(ll i=0;i<=t+10;i++) dis[i]=-inf,flow[i]=inf,vis[i]=0;//注意根據題目更改清空范圍
vis[s]=1;dis[s]=0;
while(!q.empty())
{
ll u=q.front();q.pop();
//printf("-u=%lld\n",u);
for(ll i=head[u];i!=-1;i=e[i].next)
{
ll v=e[i].to,w=e[i].cos,lim=e[i].lim;
if(lim>0&&(dis[u]+w>dis[v]))
{
//printf(" v=%lld w=%lld lim=%lld dis[%lld]=%lld dis[%lld]=%lld\n",v,w,lim,u,dis[u],v,dis[v]);
dis[v]=dis[u]+w;
flow[v]=min(flow[u],lim);
//printf("flow[%lld]=%lld flow[%lld]=%lld\n",u,flow[u],v,flow[v]);
pre[v]=i;
if(vis[v]==0)
{
vis[v]=1;
q.push(v);
}
}
}
vis[u]=0;
}
//printf("flow[%lld]=%lld\n",t,flow[t]);
return flow[t]==inf?-1:1;
}
ll slove()
{
ll mxflow=0,micost=0;
while(bfs()==1)
{
micost+=dis[t]*flow[t];
mxflow+=flow[t];
//printf("micost=%lld mxflow=%lld\n",micost,mxflow);
ll v=t;
//printf("111\n");
//printf("v=%lld\n",v);
while(1)
{
ll u=e[pre[v]^1].to;
//printf(" u=%lld\n",u);
e[pre[v]].lim-=flow[t];
e[pre[v]^1].lim+=flow[t];
v=u;
if(u==s) break;
}
}
printf("%lld\n",micost);
}
void init()
{
memset(head,-1,sizeof(head));
cnt=0;
}
ll a[maxn],b[maxn],c[maxn];
int main()
{
int t1;
scanf("%d",&t1);
while(t1--)
{
ll M;
scanf("%lld %lld %lld",&n,&m,&M);
for(ll i=1;i<=n;i++) scanf("%lld",&a[i]);
for(ll i=1;i<=n;i++) scanf("%lld",&b[i]);
for(ll i=1;i<=n;i++) scanf("%lld",&c[i]);
s=0;t=4*n+4;
ll s1=4*n+1;
init();add(s,s1,m,0);
for(int i=1;i<=n;i++)
{
add(s1,i,1,0);
}
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=n;j++)
{
add(i,n+j,1,(a[j]+b[i])*(a[j]^b[i])%M);
//printf("i=%lld j=%lld w=%lld\n",i,n+j,(a[j]+b[i])*(a[j]^b[i])%M);
}
}
for(ll i=1;i<=n;i++) add(n+i,2*n+i,1,0);
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=n;j++)
{
add(2*n+i,n*3+j,1,(a[i]+c[j])*(a[i]^c[j])%M);
//printf("i=%lld j=%lld w=%lld\n",2*n+i,3*n+j,(a[i]+c[j])*(a[i]^c[j])%M);
}
}
for(ll i=1;i<=n;i++) add(3*n+i,t,1,0);
slove();
}
/*scanf("%lld %lld %lld %lld",&n,&m,&s,&t);
for(ll i=1;i<=m;i++)
{
ll u,v,w,s;
scanf("%lld %lld %lld %lld",&u,&v,&w,&s);
add(u,v,w,s);
//add(u,v,w);
}*/
//slove();
}
/*
1111
2 2 10
1 9
9 1
10 10
*/
8 / 16 Problem C CFGym 102801C Function---
9 / 18 Problem D CFGym 102801D Fall Guys---
2 / 29 Problem E CFGym 102801E Liner vectors !!!
一道找規律的題目,結果在那里存一萬個數亂搞,時間花了還沒寫出來
題意是找到n個數,這n個數的二進制中的一的個數為k,而且其中一個數不能被其他數異或得到,求字典序最小的n個數
簡單講一下規律,首先k為偶數一定沒有答案,如果n要大於c[n][k]也沒有答案,一般規律就是假如n為9,k為5,那么答案就為:
000011111
000101111
000110111
000111011
000111101
000111110
001001111
010001111
100001111
對於前k+1個,就是對於一個(k+1)*(k+1)的矩陣,對角線上是0,其他位置都是1
剩下的是對於第2個求得的值,其中第一個1往左移一位
代碼
#include<stdio.h>
#include<algorithm>
using namespace std;
#define ll long long
ll ans[100];
ll er[70];
int main(){
er[0]=1;
for(int i=1;i<=63;i++)er[i]=er[i-1]*2ll;
int t;
scanf("%d",&t);
while(t--){
ll n,k;
scanf("%lld %lld",&n,&k);
if(n==1&&k==1){
printf("1\n");
continue;
}
ll z=min(k,n-k);
ll now=1;
int flag=0;
for(ll i=1;i<=z;i++){
now=now*(n-i+1)/i;
if(now>=n){
flag=1;
break;
}
}
if(flag==0){
printf("-1\n");
continue;
}
if(k%2==0||n==k){
printf("-1\n");
continue;
}
ans[1]=er[k]-1;
for(int i=2;i<=min(k+1,n);i++){
ans[i]=er[k+1]-1-er[k-i+1];
}
for(int i=k+2;i<=n;i++){
ans[i]=er[i-1]+er[k-1]-1;
}
for(int i=1;i<=n;i++){
printf("%lld",ans[i]);
if(i==n){
printf("\n");
}
else{
printf(" ");
}
}
}
}
Problem F CFGym 102801F Splendor???
8 / 17 Problem G CFGym 102801G Halli Galli ---
7 / 24 Problem H CFGym 102801H PepperLa's String !!!
隊內倒數可還行 這道題人均會寫
至於為何卡這題
我想我們對於實現沒有想清楚 就開始寫了
首先要滿足長度最小 其次才是字典序最小
字典序關系 數字<大寫字母<小寫字母
一開始我們先把所有連續的字母進行壓縮(不可能從中間斷開 成兩端 長度肯定更長)寫成字母+數量的形式
那么數量可以減少有三種情況
1.當前字母只有一個 直接刪去它
2.當前字母有兩個刪去一個
3.當前字母大於兩個 並且刪去一個以后數量表示的十六進制會縮短一位(例如 10->F)
我們先看有沒有上述三種的情況 如果沒有的話 我們直接刪去第一個字母就行
而上述三種情況只有第一種情況 可能讓字典序變小(第二種情況在字符串末尾也行 但是我們把他歸類為其他情況)那就是當前字母字典序大於后面的字母(或當前字母在最后位置)
對於其他情況來說 因為它們會增大字典序 所以這樣的修改放在盡量靠后的位置
綜上所述就是
1.如果無法改變數量 就刪掉第一個
2.否則 如果是第一類情況 並且可以減小字典序 那么就優先考慮這種
3.其他情況 考慮位置最靠后的那種
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+100;
char s[N],now[N];
int cnt[N];
int trans(int x,int print){
vector<char>q;
while(x){
q.push_back((x%16)>9?(x%16-10+'A'):(x%16+'0'));
x/=16;
}
reverse(q.begin(),q.end());
if(print) for(int j = 0; j < (int)q.size(); j++) printf("%c",q[j]);
return q.size();
}
void solve(){
int len = strlen(s+1),ct = 0,m = 0;
for(int i = 1; i <= len; i++){
if(i==1||s[i]!=s[i-1]){
ct=1;
}else ct++;
if(i==len||s[i]!=s[i+1]){
now[++m]=s[i];
cnt[m]=ct;
}
}
int del_pos=1;
for(int i = 1; i <= m; i++){
if(cnt[i]==1){
del_pos=i;
if(i==m||now[i]>now[i+1]) break;
}
if(cnt[i]==2||trans(cnt[i],0)>trans(cnt[i]-1,0))
del_pos=i;
}
cnt[del_pos]--;
for(int i = 1; i <= m; i++){
if(cnt[i]==0) continue;
if(cnt[i]==1){
printf("%c",now[i]);
continue;
}
printf("%c",now[i]);
trans(cnt[i],1);
}
puts("");
}
int main(){
while(~scanf("%s",s+1)){
solve();
}
return 0;
}
8 / 20 Problem I CFGym 102801I PepperLa's Cram School ---
9 / 13 Problem J CFGym 102801J Color the blocks ---
0 / 2 Problem K CFGym 102801K PepperLa's Boast !!!
容易推出轉移方程
dp[i][j]=max(dp[i-1][j-1],dp[i-1][j],dp[i][j-1]) (a[i][j]>0)
dp[i][j]=max(dp[i][j],dp[x][y]-u+a[i][j]) (i-x<=k,j-y<=k)
用二維的單調隊列維護即可 比較新穎的用法 一邊dp一邊維護單調隊列
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3+100;
typedef long long ll;
struct node{
ll val;
int id;
};
deque<node>col[N],rol;
ll a[N][N],dp[N][N];
int main(){
int n,m,k,u;
while(~scanf("%d%d%d%d",&n,&m,&k,&u)){
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++){
scanf("%lld",&a[i][j]);
}
memset(dp,-1,sizeof(dp));
dp[1][1]=a[1][1];
for(int i = 1; i <= m; i++) col[i].clear();
for(int i = 1; i <= n; i++){
rol.clear();
for(int j = 1; j <= m; j++){
while(col[j].size()&&col[j].front().id<i-k) col[j].pop_front();
while(rol.size()&&rol.front().id<j-k) rol.pop_front();
if(a[i][j]>0){
if(~dp[i-1][j]) dp[i][j]=max(dp[i][j],a[i][j]+dp[i-1][j]);
if(~dp[i][j-1]) dp[i][j]=max(dp[i][j],a[i][j]+dp[i][j-1]);
if(~dp[i-1][j-1]) dp[i][j]=max(dp[i][j],a[i][j]+dp[i-1][j-1]);
if(col[j].size()){
while(rol.size()&&rol.back().val<=col[j].front().val) rol.pop_back();
rol.push_back((node){col[j].front().val,j});
}
if(rol.size()) dp[i][j]=max(dp[i][j],rol.front().val+a[i][j]-u);
if(col[j].size()) rol.pop_back();
}
if(dp[i][j]>=u){
while(col[j].size()&&col[j].back().val<=dp[i][j]) col[j].pop_back();
col[j].push_back((node){dp[i][j],i});
}
if(col[j].size()){
while(rol.size()&&rol.back().val<=col[j].front().val) rol.pop_back();
rol.push_back((node){col[j].front().val,j});
}
}
}
printf("%lld\n",dp[n][m]);
}
return 0;
}