2018/7/7-纪中某C组题【jzoj1494,jzoj1495,jzoj1496,jzoj1497】
前言
290卡成145,十分開心。
正題
T1:密碼
大意
N個數乘起來
考試時
看起來十分簡單的高精乘單精
解題思路
10241024其實是10241024高精乘高精了解一下,30分QAQ
代碼(高精乘高精我就不解釋了吧)
#include<cstdio> #include<cstring> #define M 2500 using namespace std; long long a[M+1],n,k[M],b[M+1],l,lo; void read() {memset(k,0,sizeof(k));char c[51];scanf("%s",c);l=strlen(c);for (int i=1;i<=l;i++)k[i]=c[l-i]-48; } void add() {for (int i=1;i<=lo;i++){for (int j=1;j<=l;j++){b[i+j-1]+=a[i]*k[j];b[i+j]+=b[i+j-1]/10;b[i+j-1]%=10;}}lo=-1;for (int i=M;i>=1;i--){if (b[i]!=0&&lo==-1) lo=i;a[i]=b[i];b[i]=0;} } void write() {int w=M;while (w>1&&!a[w]) w--;int flag=w;for (;w;w--)printf("%d",a[w]); } int main() {scanf("%d",&n);a[1]=1;lo=1;for (int i=1;i<=n;i++){read();add();}write(); }T2:寶石
大意
有一個m?mm?m的矩陣,然后nn個寶石價值不同在矩陣里,然后一個為k?kk?k的東西要求碰到大寶石價值最大。
考試時
敲了一個矩陣前綴和然后O(n2)O(n2)暴力枚舉拿了60分
解題思路
定義一個長度m,高度為k的掃描線,然后在線內的用線段樹維護最大長度為k的字段和。
代碼
#include<cstdio> #include<algorithm> using namespace std; struct treenode{int l,r,w,lazy; }a[300001]; struct node{int x,y,w; }d[50001]; int m,n,k,maxs; void build(int k,int l,int r) {a[k].l=l;a[k].r=r;if (l==r) return;int mid=(l+r)/2;build(k*2,l,mid);build(k*2+1,mid+1,r); } void ddata(int k) {a[k*2].w+=a[k].lazy;a[k*2+1].w+=a[k].lazy;a[k*2].lazy+=a[k].lazy;a[k*2+1].lazy+=a[k].lazy;a[k].lazy=0; } void updata(int l,int r,int k,int num) {if (a[k].l==l&&a[k].r==r){a[k].w+=num;a[k].lazy+=num;return;}ddata(k);if (a[k*2].r>=r) updata(l,r,k*2,num);else if (a[k*2+1].l<=l) updata(l,r,k*2+1,num);else updata(l,a[k*2].r,k*2,num),updata(a[k*2+1].l,r,k*2+1,num);a[k].w=max(a[k*2].w,a[k*2+1].w); } //以上為線段樹 bool cmp(node x,node y) {return x.y<y.y; } int main() {scanf("%d%d%d",&m,&n,&k);for (int i=1;i<=n;i++){scanf("%d%d%d",&d[i].x,&d[i].y,&d[i].w);}sort(d+1,d+1+n,cmp);//排序build(1,1,m);//建樹int w=1;//掃描上限for (int i=1;i<=n;i++)//枚舉下限{while (d[i].y-d[w].y>k)//更新上限{updata(d[w].x,min(d[w].x+k,m),1,-d[w].w);//去掉w++;}updata(d[i].x,min(d[i].x+k,m),1,d[i].w);//維護字段和maxs=max(maxs,a[1].w);//查詢最大字段和}printf("%d",maxs); }T3:頁
大意
一個序列,每次取中間的放到頭或尾,求至少多少次可以變為單調遞增。
考試
剛開始打了個貪心,然后發現數據不是很大,然后打了一個廣搜,為了防止超時打了一個卡時間的結果就炸了30。把卡時間的去掉后100
解題思路
廣搜然后map庫(或哈希表)去重
代碼
#include<cstdio> #include<map> #include<string> #include<iostream> #include<queue> #include<ctime> using namespace std; map<string,int> f; string s,mb,state[362881]; int a[10],n,head,tail; void bfs() {if (s==mb){printf("0");return;}state[1]=s;f[s]=1;head=0;tail=1;do{s=state[++head];int k=f[state[head]];for (int i=1;i<=n/2;i++)swap(s[i],s[n/2+1]);//放在頭if (!f[s]){state[++tail]=s;f[s]=k+1;if (s==mb)//已經完成{printf("%d",k);return;}}s=state[head];for (int i=n;i>n/2+1;i--)swap(s[i],s[n/2+1]);//放在尾if (!f[s]){state[++tail]=s;f[s]=k+1;if (s==mb)//已經完成{printf("%d",k);return;}}}while (head<tail);printf("No Answer"); } int main() {scanf("%d",&n);s+="*";mb+="*";for (int i=1;i<=n;i++){scanf("%d",&a[i]);s+=i+48;mb+=i+48;}for (int i=1;i<n;i++)for (int j=i+1;j<=n;j++){if (a[i]>a[j]){swap(a[i],a[j]);swap(mb[i],mb[j]);//確定目標狀態}}bfs();return 0; }T4:景點中心
大意
有n個景點構成一顆樹,然后每個景點有不同數量的學生,邊有不同的長度,定一個景點為中心要求所有學生到達這個點的路徑長度和最小。
考試
敲出了正解,結果沒注意范圍30QAQ。
解題思路
一棵樹然后就想到了樹形dp,然后想起來有個東西叫二次掃描換根法,之后就推出了正解:
首先我們先以1為根進行一遍求出f[i]f[i]和zn[i]zn[i],f[i]f[i]是表示點i子樹的學生走到點i的路徑長度和,然后zn[i]zn[i]表示點i的子樹的學生人數總和。
然后我們就求出了以i為根節點的情況下的路徑和,我們嘗試推到第二層的節點。
這是一顆以1為根節點的樹,然后我們變為以2為根節點
然后我們會發現
圖中綠色部分(原第二個節點的子樹部分)都少走了一條路w,而圖中紅色部分(其余部分)都多走了一條路w,所以我們可以自己計算:
從而 O(1)O(1)的時間復雜度內計算出下一個點為根時的距離和。
代碼
#include<cstdio> #include<algorithm> #include<cstring> #define N 1000001 using namespace std; struct node{int next,to,w; }a[N]; int ls[N],tot,n,x,y,w,v[N]; long long c[N],f[N],zn[N],maxs,num[N]; void addl(int x,int y,int w) {a[++tot].to=y;a[tot].w=w;a[tot].next=ls[x];ls[x]=tot; } void dp(int x,int dep)//第一次掃描 {v[x]=true;zn[x]=num[x];//記錄人數f[x]=num[x]*dep;//統計for (int i=ls[x];i;i=a[i].next){int y=a[i].to;if (!v[y]){dp(y,dep+a[i].w);f[x]+=f[y];zn[x]+=zn[y];//累計}} } void zdp(int x,int dep,int fa,int from)//第二次掃描 {v[x]=true;if (x!=1)c[x]=c[fa]+(zn[1]-zn[x])*a[from].w-zn[x]*a[from].w;//計算if (c[x]<c[maxs]) maxs=x;for (int i=ls[x];i;i=a[i].next){y=a[i].to;if (!v[y])zdp(y,dep+a[i].w,x,i);//計算子節點} } int main() {freopen("data.txt","r",stdin);scanf("%d",&n);for (int i=1;i<=n;i++){scanf("%lld",&num[i]);}for (int i=1;i<n;i++){scanf("%d%d%d",&x,&y,&w);addl(x,y,w);addl(y,x,w);}c[0]=1e18;maxs=0;dp(1,0);memset(v,0,sizeof(v));c[1]=f[1];zdp(1,0,0,0);printf("%lld\n%lld",maxs,c[maxs]); }后續
zyc大佬太強了
m e | \ /V / / ====== / / orz orz orz orz orz orz orz orz orz/ / ====== / / orz orz orz orz orz orz orz orz orz+ =========== + orz orz orz orz orz orz orz orz orz| [zyc dalao] | orz orz orz orz orz orz orz orz orz+ =========== + orz orz orz orz orz orz orz orz orz\ \ ====== \ \ orz orz orz orz orz orz orz orz orz\ \ ====== \ \ orz orz orz orz orz orz orz orz orz總結
以上是生活随笔為你收集整理的2018/7/7-纪中某C组题【jzoj1494,jzoj1495,jzoj1496,jzoj1497】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2018/7/6-纪中某C组题【jzoj
- 下一篇: 头条文章如何段落首行缩进两个字符如何将正